Java多线程之Thread VS Runnable
程序员文章站
2022-05-05 22:49:02
...
Thread VS Runnable
Thread VS Runnable
两种方式的比较:
- Runnable方式可以避免Thread方式由于Java的单继承特性带来的缺陷
- Runnable的代码可以被多个线程(Thread实例)共享,适用于多个线程处理同一资源的情况。(同一资源指的是同一个Runnable对象)
- 安全的卖票程序需要加入同步(Synchronized)
class MyThread extends Thread{
private int tickets=5;
private String name;//窗口,也是线程的名字
public MyThread(String name) {
super();
this.name = name;
}
@Override
public void run() {
while(tickets > 0) {
tickets--;
System.out.println(name+"卖了1张票,剩余票数:"+tickets);
}
}
}
public class TicketsThread{
//共卖了15张票
public static void main(String[] args) {
//创建三个线程,模拟三个窗口卖票
MyThread mt1 = new MyThread("窗口1");
MyThread mt2 = new MyThread("窗口2");
MyThread mt3 = new MyThread("窗口3");
//启动三个线程,开始卖票
mt1.start();
mt2.start();
mt3.start();
}
}
class MyThread implements Runnable{
private int tickets=5;
@Override
public void run() {
while(tickets > 0) {
tickets--;
System.out.println(Thread.currentThread().getName()+"卖了1张票,剩余票数:"+tickets);
}
}
}
public class TicketsRunnable {
public static void main(String[] args) {
MyThread mt = new MyThread();
//创建三个线程来模拟三个售票窗口
Thread t1=new Thread(mt,"窗口1");
Thread t2=new Thread(mt,"窗口2");
Thread t3=new Thread(mt,"窗口3");
//说明三个窗口各卖5张票
/* MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
MyThread mt3 = new MyThread();
//创建三个线程来模拟三个售票窗口
Thread t1=new Thread(mt1,"窗口1");
Thread t2=new Thread(mt2,"窗口2");
Thread t3=new Thread(mt3,"窗口3");*/
t1.start();
t2.start();
t3.start();
}
}
总结:多使用Runnable这种方式创建线程。
线程的生命周期和守护线程
线程的生命周期:
-
就绪:创建线程对象后,调用了线程的start()方法(注意:此时线程只是进入了线程队列,等待获取CPU服务,具备了运行的条件,但并不一定已经开始运行了)
-
运行:处于就绪状态的线程,一旦获取了CPU资源,便进入到运行状态,开始执行run()方法里面的逻辑。
-
终止:线程的run()方法执行完毕,或者线程调用了stop()方法(此方法被淘汰掉了),线程便进入终止状态。
-
阻塞:一个正在执行的线程在某些情况下,由于某种原因而暂时让出了CPU资源,暂停了自己的执行,便进入了阻塞状态,如调用了sleep()方法。
Java线程有两类: -
用户线程:运行在前台,执行具体的任务
- 程序的主线程,连接网络的子线程等都是用户线程。
-
守护线程:运行在后台,为其他前台线程服务
- 特点:一旦所有用户线程都结束运行,守护线程会随JVM一起结束工作。
- 应用:
数据库连接池中的监测线程
JVM虚拟机启动后的监测线程
最常见的守护线程:垃圾回收线程
-
如何设置守护线程:
- 可以通过Thread类的setDaemon(true)方法来设置当前的线程为守护线程
- 注意:
- setDaemon(true)必须在start()方法之前调用,否则会抛出IllegalThreadStateException异常
- 在守护线程中产生的新线程也是守护线程
- 不是所有的任务都可以分配给守护线程来执行,比如读写操作或者计算逻辑
/**
* 模拟: 守护线程:很长一段时间向文件中写数据
* 主线程:会阻塞等待来自键盘的输入,一旦获取用户的输入阻塞解除,主线程继续运行,直到结束(守护线程也会随JVM一起结束运行)。
*/
class DaemonThread implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("进入守护线程:"+Thread.currentThread().getName());
try {
writeToFile();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("退出守护线程:"+Thread.currentThread().getName());
}
private void writeToFile() throws Exception{
File filename = new File("daemon.txt");
OutputStream os = new FileOutputStream(filename,true);
int count=0;
while(count <99) {
os.write(("\r\nword"+count).getBytes());
System.out.println("守护线程"+Thread.currentThread().getName()
+"向文件中写入了word"+count++);
Thread.sleep(1000);
}
}
}
public class DaemonThreadDemo {
public static void main(String[] args) {
System.out.println("进入主线程"+Thread.currentThread().getName());
DaemonThread dt = new DaemonThread();
Thread t = new Thread(dt);
t.setDaemon(true);
t.start();
Scanner sc = new Scanner(System.in);
sc.next();
System.out.println("退出了主线程"+Thread.currentThread().getName());
}
}
上一篇: 多线程-出现非线程安全的底层原因
推荐阅读
-
Android开发笔记之:Handler Runnable与Thread的区别详解
-
Java多线程同步工具类之Semaphore
-
Java多线程系列--“JUC锁”06之 Condition条件
-
Java线程Thread的状态解析以及状态转换分析 多线程中篇(七)
-
Java中实现多线程继承Thread类与实现Runnable接口的区别
-
Java多线程Part3:线程(Thread)的状态和等待唤醒机制
-
java多线程学习之从正常到自残
-
Java的Thread,Runnable、Callable、Future、FutureTask、Executors,ExecutorService
-
用 JMX 作简单之 Java VM 监视(Part 1) JavaSUNJDK多线程J2SE
-
Java多线程并发编程中并发容器第二篇之List的并发类讲解