关于Java线程

Posted blog-lnw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于Java线程相关的知识,希望对你有一定的参考价值。

一、线程具有优先级(priority)

线程的优先级分为十个等级,分别从1到10,优先级的高低决定了线程被CPU执行的先后顺序。(但不是绝对的,只是优先级越高,抢占CPU的几率就越大)

Thread类有三个关于线程优先级的静态变量:MAX_PRIORITY表示最大优先级,为10;MIN_PRIORITY表示最先优先级,为1;NORM_PRIORITY表示普通优先级,为5.

二、线程的调度

线程的调度有两种模型:分时模型和抢占模型

分时模型:线程在指定的时间里执行(在CPU上)

抢占模型:线程一旦获得执行权,就一直执行下去。(Java语言支持的是抢占模型)

(重点)三、Java的Thread线程类和Runnable接口

创造线程有两种方法,一种是继承Thread类,一种是实现Runnable接口

Thread类是线程类,利用Thread的子类创造线程

Runnable是接口,只有一个run()方法。相当于重写了Thread类的run()方法。但实现Runnable接口的类必须作为另一个Thread类对象的参数,以此来创造线程。

继承Thread类创造线程 1


1 class MyThread extends Thread{  //继承Thread类 2 private String who; 3 public MyThread(String str) { 4 who=str; //初始化who 5 } 6 //覆盖Thread的run方法,线程的开始也是从run开始的 7 public void run() { 8 System.out.println(who+"最先运行"); 9 } 10 } 11 public class UseThread { 12 public static void main(String[] args) { 13 MyThread you=new MyThread("你"); 14 MyThread she=new MyThread("她"); 15 she.setPriority(1); //设置she的优先级 16 you.start(); //你 线程开始 17 she.start(); //她 线程开始 18 //注意是start() 19 System.out.println("you的优先级为"+you.getPriority()); 20 System.out.println("she的优先级为"+she.getPriority()); 21 System.out.println("main结束"); 22 } 23 }

技术分享图片

实现Runnable接口创造线程

 1 class MyRun implements Runnable{
 2     private String who;
 3     public MyRun(String str) {
 4         who=str;
 5     }
 6     @Override
 7     public void run() {
 8         for(int i=0;i<5;i++) {
 9             try {
10                 //因为是实现接口所以需要加前缀Thread
11                 Thread.sleep((int)(1000*Math.random()));
12             } catch (Exception e) {
13                 System.out.println(e.toString());
14             }
15             System.out.println(who+"正在运行!!");
16         }
17     }
18 }
19 public class UseRunnable  {
20     public static void main(String[] args) {
21         /*
22         MyRun you=new MyRun("你");
23         MyRun she=new MyRun("她");
24         //将实现接口的对象床底给Thread并生成Thread对象
25         Thread t1=new Thread(you);
26         Thread t2=new Thread(she);
27         t1.start();
28         t2.start();
29         System.out.println("main运行结束");
30         */
31         //让you和she逐个运行
32         MyRun you=new MyRun("你");
33         MyRun she=new MyRun("她");
34         //将实现接口的对象床底给Thread并生成Thread对象
35         Thread t1=new Thread(you);
36         Thread t2=new Thread(she);
37         t1.start();
38         try {
39             t1.join();    //使用join()时,需让此时的线程先执行完,下一个线程才能执行
40         } catch (InterruptedException e) {
41             System.out.println(e.toString());
42         }
43         t2.start();
44         try {
45             t2.join();
46         } catch (InterruptedException e) {
47             System.out.println(e.toString());
48         }
49         System.out.println("main运行结束");
50     }
51 }

技术分享图片

(main方法也是一个线程)

四、关于线程的数据共享

如果线程的操作是共享某个数据,一般都是用实现Runnable接口的类,把数据放在Runnable接口的类中,然后再创造线程。

比如三个线程在售票

 1 class ThreadShare implements Runnable{
 2     private int tickets=10;
 3     @Override
 4     public void run() {
 5         while(true) {
 6             if(tickets>0) {
 7                 System.out.println(Thread.currentThread().getName()+"售机票第"+tickets--+"号");
 8             }
 9             else
10                 System.exit(0);
11         }
12     }
13     
14 }
15 public class ThreadShareMain {
16     public static void main(String[] args) {
17         ThreadShare t=new ThreadShare();
18         //用此对象t作为参数创建三个线程
19         Thread t1=new Thread(t,"第1售票窗口");
20         Thread t2=new Thread(t,"第2售票窗口");
21         Thread t3=new Thread(t,"第3售票窗口");
22         t1.start();
23         t2.start();
24         t3.start();
25     }
26 }

技术分享图片

五、关于同步线程

线程在一个完整操作的所有动作的执行过程中,都占有相关资源而不被打断。

临界资源:在一个时刻只能被一个线程访问的资源

临界代码:访问临界资源的那段代码

六、“互斥锁”机制

Java每个对象都有一个“互斥锁”与之连接。一个对象只有一个互斥锁。一个线程只有获得互斥锁后,对其进行操作,而另一个线程只能处于等待状态。所以利用对一个对象互斥锁的争夺,可以实现不同线程的互斥效果。

七、synchronized关键字标识同步的资源

格式一:同步语句

Synchronized(对象){

  临界代码段

}

格式二:同步方法

public synchronized 返回类型 方法名(){

  方法体

}

synchronized的功能是先判断对象或方法的互斥锁是否存在,若存在就获得互斥锁,然后执行紧随其后的临界代码或方法体;如果对象的互斥锁不存在(已被其他线程拿走),就进入等待状态,直到获得互斥锁。

synchronized很好的解决像银行业务取款并发的情况

 1 //模拟银行账户类
 2 class Mbank{
 3     private static int sum=2000;
 4     //修饰线程同步的方法
 5     public synchronized static void take(int k) {
 6         int temp=sum;
 7         temp-=k;
 8         try {
 9             Thread.sleep((int)(1000*Math.random()));
10         } catch (InterruptedException e) {
11             e.toString();
12         }
13         sum=temp;
14         System.out.println(Thread.currentThread().getName()+"sum="+sum);
15     }
16 }
17 //模拟用户取款
18 class Customer extends Thread{
19     public void run() {
20         for(int i=0;i<4;i++) {
21             Mbank.take(100);  // 用户每次取出100,取四次
22         }
23     }
24 }
25 
26 //调用线程的主类
27 public class SynchronizedThread {
28     public static void main(String[] args) {
29         Customer c1=new Customer();
30         Customer c2=new Customer();
31         c1.start();
32         c2.start();
33     }
34 }

技术分享图片

八、线程之间的通信

一个线程的执行,需要另一个线程配合,就称作线程的通信

例如:售票操作只有当有存票才能进行售票,不然只有当存票操作后才能进行售票。

线程的通信需要用到java.lang.Object类的三个方法:

wait():线程A执行了对象x的同步代码(synchronized)里的wait()方法,该线程暂停进行,然后进入对象x的等待队列,并释放对象x的互斥锁。直到其他线程在对象x上调用notify()或notifyAll()方法,才能够重新获得对象x的互斥锁。

notify():唤醒正在等待该对象互斥锁的第一个线程

notifyAll():唤醒正在等待该对象互斥锁的所有线程,具有最高优先级的线程首先被唤醒

(wait方法必须写在try-catch里面)

写一个简单的存票售票程序:

 1 //模拟存票与售票
 2 class Tickets{
 3     protected int size;//总票数
 4     int number=0;     //票号
 5     boolean available=false;    //表示当前是否有票可售
 6     public Tickets(int n) {
 7         this.size=n;
 8     }
 9     /*
10      * 同步方法,实现存票
11      */
12     public synchronized void put() {
13         if(available) {    //如果还有剩余票就等待
14             try {
15                 wait();
16             } catch (Exception e) { }
17         }
18         System.out.println("存入第【"+(++number)+"】号票");
19         available=true;
20         notify();    //存票后唤醒售票线程开始售票
21     }
22     /*
23      * 同步方法,实现售票
24      */
25     public synchronized void sell() {
26         if(!available) {    //如果没有票,则售票线程等待
27             try {
28                 wait();
29             } catch (Exception e) {    }
30         }
31         System.out.println("售出第【"+(number)+"】号票");
32         available=false;
33         notify();        //售票后唤醒存票线程开始存票
34         if(number==size)number=size+1;    //在售完最后一张票后,设置一个结束标志
35         //number>size表示售票结束
36     }
37 }
38 //存票线程类
39 class Producer extends Thread{
40     Tickets t=null;
41     public Producer(Tickets t) {
42         this.t=t;
43     }
44     public void run() {
45         while(t.number<t.size) {
46             t.put();
47         }
48     }
49 }
50 class Consumer extends Thread{
51     Tickets t=null;
52     public Consumer(Tickets t) {
53         this.t=t;
54     }
55     public void run() {
56         while(t.number<=t.size) {
57             t.sell();
58         }
59     }
60 }
61 public class ThreadNotify {
62     public static void main(String[] args) {
63         Tickets t=new Tickets(10);
64         new Producer(t).start();    //存票线程开始
65         new Consumer(t).start();    //售票线程开始
66     }
67 }

技术分享图片


以上是关于关于Java线程的主要内容,如果未能解决你的问题,请参考以下文章

java中的进程,线程,线程池总结

Java进阶之光!2021必看-Java高级面试题总结

java开发的项目案例,大厂内部资料

Java工程师面试题,二级java刷题软件

关于Java锁

java线程