多线程的两种实现方法(Runnable接口和Thread类)


方式一:实现Runnable接口

1,自定义多线程类,并实现Runnable接口

2,添加父接口中未实现的run()方法,run()方法里面放着的是我们的业务代码

3,创建自定义对象,只创建一次,作为业务对象存在

4,创建对个Thread线程类对象,并且将业务对象交给线程对象来完成

5,以多线程的方式启动多个线程对象

优点:自定义线程只是实现了Runnable接口,后续还可以继承其他类,多线程可以共享同一个target对象,非常适合多个相同线程来处理同一份资源的情况(比如:多个窗口售票的场景)

缺点:编程复制,如果想访问当前线程则需要使用Thread.currentThread()静态对象的getName() 方法来获取当前线程

代码如下:

 package cn.tedu.thread;

public class TestRunnableV2 {
public static void main(String[] args) {
TicketsRunnableV2 target=new TicketsRunnableV2();
Thread t1=new Thread(target);
Thread t2=new Thread(target);
Thread t3=new Thread(target);
Thread t4=new Thread(target);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
/*
同步锁:
相当于给容易出现问题的代码加了一把锁,包裹了所有可能会出现数据安全问题的代码加锁之后,
就有了同步(排队)的效果,但是加锁的范围需要考虑
不能太大:太大效率低下
不能太小:出现数据安全问题
*/
class TicketsRunnableV2 implements Runnable{
int tickets=100;
@Override
public void run() {
while (true){
/*
同步代码块:synchronizde(锁对象){会出现安全隐患的所有代码}
在同步代码块中的代码,同一时刻只会被一个线程执行
注意:同步代码块必须保证所有线程对象使用同一一把唯一的锁
*/
synchronized (TicketsRunnableV2.class) {//同步锁的唯一性,解决重卖的情况
if(tickets>0){//解决多卖的情况
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "==" + tickets--);
}
if (tickets <= 0) break;
}
}
}
}

方式一:继承Thread类
1,继承Thread类,自定义类并且继承Thread类
2,在自定义类中重写Thread类的run()方法,这run()方法存放的是我们自己的业务代码
3,创建自定义线程对象(该步骤对应线程状态的新建状态)
4,调用start()方法以多线程的方式将多个线程对象加入到线程就绪队列中,等待OS选中
优点:编写简单
缺点:继承的耦合度较高,自定义的线程类继承了Thread类,后续无法继承其他类对象

代码如下:
package cn.tedu.thread;
/*
需求:设计多线程编程模型,4个窗口共计售票100
*/
public class TestTickets {
public static void main(String[] args) {
ThreadTickets t1=new ThreadTickets();
ThreadTickets t2=new ThreadTickets();
ThreadTickets t3=new ThreadTickets();
ThreadTickets t4=new ThreadTickets();
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class ThreadTickets extends Thread{
/*
问题:4个线程对象共计售票400张,原因是创建了4个不同的线程对象
每个对象都把票数tickets看作自己独有的成员变量,互不影响
解决方案:将票数设置为静态,让全局所以对象共享
*/
static int tieckets=100;//静态变量供类使用,不会随着对象的创建而加载
@Override
public void run() {
while (true){
synchronized (ThreadTickets.class) {//使用类名的字节码文件来做为唯一的同步锁标识
if(tieckets>0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() + "=" + tieckets--);
}
if (tieckets <= 0) break;
}
}
}
}

最后:总结几个概念
多线程安全问题:线程产生多卖或者重卖的现象
如何判断程序是否存在线程安全问题:1,多线程程序;2,存在共享数据;3,多条语句操作共享数据

同步:体现了排队的效果,即同一时间内只能有一个线程独占资源,其他线程没有权利访问该资源(坏处:效率比较低,但是保证了安全隐患)
异步:体现了多线程抢占资源的效果,线程互不等待,互抢资源(坏处:安全有隐患,但是效率比较高)





免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM