欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java多线程记录(包含案例)

程序员文章站 2022-05-18 17:47:52
线程是程序的执行单元,执行路径。是程序使用CPU的最基本单位 多线程 -- 程序有多条执行路径,提高应用进程的使用率 进程中线程越多,抢到CPU执行权概率越高。线程的执行有随机性 Java程序的运行原理: 由Java命令启动JVM,JVM启动就相当于启动了一个进程,接着由该程序创建了一个主线程去调用 ......

线程是程序的执行单元,执行路径。是程序使用cpu的最基本单位

多线程 -- 程序有多条执行路径,提高应用进程的使用率

进程中线程越多,抢到cpu执行权概率越高。线程的执行有随机性

 

java程序的运行原理:

由java命令启动jvm,jvm启动就相当于启动了一个进程,接着由该程序创建了一个主线程去调用main方法

jvm的启动是多线程的,因为垃圾回收线程也要启动,否则容易出现内存溢出。(gc线程和主线程)

 

java多线程程序:

方法1:继承thread类,并重写run()方法,创建对象,执行对象。

  run()方法: thread类中的run()用来包含那些被线程执行的代码(封装被线程执行的代码)(不单独调用run方法(直接调用是普通方法),调用start())

  start()方法:首先启动了线程,然后再由jvm去调用该线程的run()方法

方法2:实现runnable接口

  a:自定义类实现runnable

  b:重写run()方法

  c:创建myrunnable类的对象 

  d:创建thread类的对象,把c步骤的对象作为构造参数传递

解决了java单继承的局限性,适合多个相同程序代码去处理同一个资源的情况,把线程相同的代码,数据有效分离

 

一些内建方法:

public final string getname()   //获取线程名称
public final string setname():    //设置线程名称
public static thread currentthread():    //返回当前正在执行的线程对象

 

抢占式调度模型(java):优先让优先级高的线程使用cpu

public final int getpriority():   //返回线程对象的优先级
public final void setpriority(): //设置线程优先级

优先级范围1-10,默认为5,最低为1,最高为5

 

线程控制:

public static void sleep(long millis)    //线程休眠
public final void join():   //线程加入   (等待线程终止)
public static void yield():  //线程礼让 暂停当前正在执行的线程对象,并执行其他线程
//让多个线程的执行更加和谐,但不能保证
public final void setdaemon(boolean on): //设置守护线程
//当正在运行的线程都是守护线程时,jvm退出,该方法必须在启动线程前调用
public void interrupt(): //中断线程,把线程的状态终止,并抛出一个interruptexception

 

线程的生命周期:(图解)

Java多线程记录(包含案例)

 

线程同步:synchronized关键字 

将多条语句操作的共享数据代码包成一个整体,让某个线程在执行的时候别人不执行

前提:多个线程;  注意:多个线程使用同一个锁对象

优点:解决了多线程的安全问题

缺点:当线程相当时,因为每个线程都会去判断同步上的锁,很耗费资源,无形中降低了程序的运行效率,容易产生死锁

使用同步代码块或者同步方法

 

死锁:

死锁代码举例:

1 public class mylock {
2     // 创建两把锁对象
3     public static final object obja = new object();
4     public static final object objb = new object();
5 }
 1 public class deadlock extends thread {
 2 
 3     private boolean flag;
 4 
 5     public deadlock(boolean flag) {
 6         this.flag = flag;
 7     }
 8 
 9     @override
10     public void run() {
11         if (flag) {
12             synchronized (mylock.obja) {
13                 system.out.println("if obja");
14                 synchronized (mylock.objb) {
15                     system.out.println("if objb");
16                 }
17             }
18         } else {
19             synchronized (mylock.objb) {
20                 system.out.println("else objb");
21                 synchronized (mylock.obja) {
22                     system.out.println("else obja");
23                 }
24             }
25         }
26     }
27 }
1 public class dielockdemo {
2     public static void main(string[] args) {
3         deadlock dl1 = new deadlock(true);
4         deadlock dl2 = new deadlock(false);
5 
6         dl1.start();
7         dl2.start();
8     }
9 }

 

等待唤醒机制:

object类提供三个方法:

wait() :等待

notify():唤醒单个线程

notifyall():唤醒所有线程

为什么不在thread类中: 因为这些方法必须通过锁对象调用,而锁对象可以是任意锁对象,所以定义在object类中

 

semaphore信号量:

信号量(semaphore),又被称为信号灯,在多线程环境下用于协调各个线程, 以保证它们能够正确、合理的使用公共资源。信号量维护了一个许可集,我们在初始化semaphore时需要为这个许可集传入一个数量值,该数量值代表同一时间能访问共享资源的线程数量。

线程可以通过acquire()方法获取到一个许可,然后对共享资源进行操作,注意如果许可集已分配完了,那么线程将进入等待状态,直到其他线程释放许可才有机会再获取许可,线程释放一个许可通过release()方法完成,"许可"将被归还给semaphore。

 

多线程案例:

电影院卖票:电影院一共有100张票,有三个窗口卖票,模拟电影院售票:

使用同步代码块:

public class sellticket implements runnable {
    // 定义100张票
    private int tickets = 100;
    //创建锁对象
    private object obj = new object();
    
    @override
    public void run() {
        while (true) {
            synchronized (obj) {
                if (tickets > 0) {
                    try {
                        thread.sleep(100);
                    } catch (interruptedexception e) {
                        e.printstacktrace();
                    }
                    system.out.println(thread.currentthread().getname()
                            + "正在出售第" + (tickets--) + "张票");
                }
            }
        }
    }
}
public class sellticketdemo {
    public static void main(string[] args) {
        // 创建资源对象
        sellticket st = new sellticket();

        // 创建三个线程对象
        thread t1 = new thread(st, "窗口1");
        thread t2 = new thread(st, "窗口2");
        thread t3 = new thread(st, "窗口3");

        // 启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}

使用同步方法:

 1 package lab2;
 2 
 3 public class sellticket implements runnable {
 4 
 5     // 定义100张票
 6     private static int tickets = 100;
 7 
 8     @override
 9     public void run() {
10         while (true) {
11             sellticket();
12         }
13     }
14     
15      private synchronized void sellticket() {
16             if (tickets > 0) {
17             try {
18                     thread.sleep(100);
19             } catch (interruptedexception e) {
20                     e.printstacktrace();
21             }
22             system.out.println(thread.currentthread().getname()
23                         + "正在出售第" + (tickets--) + "张票 ");
24             }
25     }
26 }

使用锁方法:

 1 import java.util.concurrent.locks.lock;
 2 import java.util.concurrent.locks.reentrantlock;
 3 
 4 public class sellticket implements runnable {
 5 
 6     // 定义票
 7     private int tickets = 100;
 8 
 9     // 定义锁对象
10     private lock lock = new reentrantlock();
11 
12     @override
13     public void run() {
14         while (true) {
15             try {
16                 // 加锁
17                 lock.lock();
18                 if (tickets > 0) {
19                     try {
20                         thread.sleep(100);
21                     } catch (interruptedexception e) {
22                         e.printstacktrace();
23                     }
24                     system.out.println(thread.currentthread().getname()
25                             + "正在出售第" + (tickets--) + "张票");
26                 }
27             } finally {
28                 // 释放锁
29                 lock.unlock();
30             }
31         }
32     }
33 
34 }

 

ornamental garden problem:(使用bakery class) 花园有两个旋转门,可进可出,监控花园内的人数

volatile关键字: specifying a variable as volatile instructs the compiler to load and store the value of the variable at each use.   另外更多说明可以参考:https://www.cnblogs.com/daxin/p/3364014.html

bakery algorithm面包店算法

bakery.java

 1 package lab2;
 2 
 3 public class bakery {
 4     public int nthreads;
 5     
 6     private volatile int[] ticket;
 7     private volatile boolean[] choosing;
 8     
 9     bakery(int nth) {
10         nthreads = nth;
11         ticket = new int[nthreads];
12         choosing = new boolean[nthreads];
13         
14         for (int i = 0; i < nthreads; i++) {
15             system.out.println(i + ticket[1]);
16             ticket[i] = 0;
17             choosing[i] = false;
18         }
19     }
20     
21     private int getnextnumber() {
22         int largest = 0;
23         for (int i = 0; i < nthreads; i++) {
24             if (ticket[i] > largest)
25                 largest = ticket[i];
26         }
27         return largest + 1;
28     }
29     
30     private boolean isfavouredthread(int i, int j) {
31         if ((ticket[i] == 0) || (ticket[i] > ticket[j]))
32             return false;
33         else {
34             if (ticket[i] < ticket[j])
35                 return true;
36             else
37                 return (i < j);
38         }
39     }
40 
41     void wanttoentercs(int threadid) {
42         choosing[threadid] = true;
43         ticket[threadid] = getnextnumber();
44         choosing[threadid] = false;
45         
46         for (int otherthread = 0; otherthread < nthreads; otherthread++) {
47             while(choosing[otherthread]) {
48                 // busy-wait
49             }
50             // break any ties between threads
51             while (isfavouredthread(otherthread,threadid)) {
52                 // busy-wait
53             }
54         }
55     }
56 
57     void exitcs(int threadid) {
58         // leave critical section
59         ticket[threadid] = 0;
60     }
61 }

couter.java

 1 package lab2;
 2 
 3 public class counter {
 4     volatile int value = 0;
 5 
 6     counter() {
 7         system.out.println("total: " + value);
 8     }
 9 
10     boolean increment() {
11         int temp = value;   //read[v]
12         simulate.hwinterrupt();
13         value = temp + 1;       //write[v+1]
14         system.out.println("total: " + value);
15             return true;
16     }
17 
18     boolean decrement() {
19         int temp = value;   //read[v]
20         simulate.hwinterrupt();
21             if (temp == 0) return false;
22         simulate.hwinterrupt();
23         value = temp - 1;       //write[v+1]
24         system.out.println("total: " + value);
25             return true;
26     }
27 }
28 
29 class simulate {
30     public static void hwinterrupt() {
31         if (math.random() < 0.5)
32            try{
33                thread.sleep(200);
34            } catch(interruptedexception ie) {};
35     }
36 }

turnstile.java

 1 package lab2;
 2 
 3 /* notes:
 4  * no modifications need be made to the bakery class.  instead, the turnstile
 5  * class and counter classes are adjusted to allow for "exit" turnstiles as well
 6  * as entrance turnstiles.  this solution incorporates a system to prevent the
 7  * number of people in the gardens from being negative, so the sleep call in
 8  * this class can be commented out.  study the code in the counter and turnstile
 9  * classes to see how how this works.
10  * */
11 
12 public class gardens {
13      static turnstile west;
14      static turnstile east;
15      static turnstile westexit;
16      static turnstile eastexit;
17      static counter people;
18      static bakery bakery;
19      
20     public static void main(string[] args) {
21         people = new counter();
22         bakery = new bakery(4);
23          
24          west = new turnstile(0, true, people, bakery);
25          east = new turnstile(1, true, people, bakery);
26 
27          westexit = new turnstile(2, false, people, bakery);
28          eastexit = new turnstile(3, false, people, bakery);
29          
30          west.start();
31          east.start();
32 
33         /* 
34         try {
35             thread.sleep(5000);
36         } catch (interruptedexception e) {
37         }
38         */
39 
40         westexit.start();
41         eastexit.start();
42     }
43 }

garden.java

 1 package lab2;
 2 
 3 public class gardens {
 4      static turnstile west;
 5      static turnstile east;
 6      static turnstile westexit;
 7      static turnstile eastexit;
 8      static counter people;
 9      static bakery bakery;
10      
11     public static void main(string[] args) {
12         people = new counter();
13         bakery = new bakery(4);
14          
15          west = new turnstile(0, true, people, bakery);
16          east = new turnstile(1, true, people, bakery);
17 
18          westexit = new turnstile(2, false, people, bakery);
19          eastexit = new turnstile(3, false, people, bakery);
20          
21          west.start();
22          east.start();
23 
24         /* 
25         try {
26             thread.sleep(5000);
27         } catch (interruptedexception e) {
28         }
29         */
30 
31         westexit.start();
32         eastexit.start();
33     }
34 }

 

生产者消费者,操作列表:

buffer.java

 1 import java.util.linkedlist;
 2 import java.util.nosuchelementexception;
 3 
 4 class buffer {
 5     linkedlist<integer> queue = new linkedlist<integer>();
 6     
 7     public synchronized void write(int i) {
 8         queue.add(i);
 9     }
10 
11     public synchronized int read() {
12         try {
13             return queue.removefirst();
14         } catch(nosuchelementexception e) {
15             // the buffer is empty!?
16             return -1;
17         }
18     }
19 }

producer.java

 1 class producer implements runnable {
 2     buffer buffer;
 3 
 4     public producer(buffer b) {
 5         buffer = b;
 6     }
 7 
 8     public void run() {
 9         for(int i = 0; i < 20; i++) {
10             buffer.write(i);
11             system.out.println("thread " + thread.currentthread().getid() +
12                 " writes " + i);
13         }
14     }
15 }

consumer.java

 1 class consumer implements runnable {
 2     buffer buffer;
 3 
 4     public consumer(buffer b) {
 5         buffer = b;
 6     }
 7 
 8     public void run() {
 9         for(int i = 0; i < 10; i++) {
10             try {
11                 thread.sleep(10);
12             } catch (interruptedexception e) {
13             }
14             int x = buffer.read();
15             system.err.println("thread " + thread.currentthread().getid() +
16                 " reads " + x);
17         }
18     }
19 }

infbuffer.java

 1 public class infbuffer {
 2     public static void main(string args[]) {
 3         buffer b = new buffer();
 4         consumer c1 = new consumer(b);
 5         consumer c2 = new consumer(b);
 6         producer p = new producer(b);
 7         (new thread(c1)).start();
 8         (new thread(c2)).start();
 9         (new thread(p)).start();
10     }
11 }

 

生产者消费者,修改学生姓名和年龄并获取:(只能一打一大片,无法实现生产者生产后等待消费者消费后再产生)

1 public class student {
2     string name;
3     int age;
4 }
 1 public class setthread implements runnable {
 2 
 3     private student s;
 4     private int x = 0;
 5 
 6     public setthread(student s) {
 7         this.s = s;
 8     }
 9 
10     @override
11     public void run() {
12         while (true) {
13             synchronized (s) {
14                 if (x % 2 == 0) {
15                     s.name = "student1";
16                     s.age = 27;
17                 } else {
18                     s.name = "student2"; 
19                     s.age = 30;
20                 }
21                 x++;
22             }
23         }
24     }
25 }
 1 public class getthread implements runnable {
 2     private student s;
 3 
 4     public getthread(student s) {
 5         this.s = s;
 6     }
 7 
 8     @override
 9     public void run() {
10         while (true) {
11             synchronized (s) {
12                 system.out.println(s.name + "---" + s.age);
13             }
14         }
15     }
16 }
 1 public class studentdemo {
 2     public static void main(string[] args) {
 3         //创建资源
 4         student s = new student();
 5         
 6         //设置和获取的类
 7         setthread st = new setthread(s);
 8         getthread gt = new getthread(s);
 9 
10         //线程类
11         thread t1 = new thread(st);
12         thread t2 = new thread(gt);
13 
14         //启动线程
15         t1.start();
16         t2.start();
17     }
18 }

 

生产者消费者,修改学生姓名和年龄并获取:(使用等待唤醒机制改进)

1 public class student {
2     string name;
3     int age;
4     boolean flag;  //添加一个标记,默认为false,表示生产者是否生成值
5 }
 1 public class setthread implements runnable {
 2 
 3     private student s;
 4     private int x = 0;
 5 
 6     public setthread(student s) {
 7         this.s = s;
 8     }
 9 
10     @override
11     public void run() {
12         while (true) {
13             synchronized (s) {
14                 //判断有没有
15                 if(s.flag) {
16                     try {
17                         s.wait();
18                     } catch (interruptedexception e) {
19                         e.printstacktrace();
20                     }
21                 } 
22                 
23                 if (x % 2 == 0) {
24                     s.name = "student1";
25                     s.age = 27;
26                 } else {
27                     s.name = "student2"; 
28                     s.age = 30;
29                 }
30                 x++;
31                 
32                 //修改标记
33                 s.flag = true;
34                 //唤醒线程
35                 s.notify();
36             }
37         }
38     }
49 }
 1 public class getthread implements runnable {
 2     private student s;
 3 
 4     public getthread(student s) {
 5         this.s = s;
 6     }
 7 
 8     @override
 9     public void run() {
10         while (true) {
11             synchronized (s) {
12                 if (!s.flag) {
13                     try {
14                         s.wait();
15                     } catch (interruptedexception e) {
16                         e.printstacktrace();
17                     }
18                 }
19                 system.out.println(s.name + "---" + s.age);
20                 
21                 //修改标记
22                 s.flag = false;
23                 //唤醒线程
24                 s.notify();
25                 
26             }
27         }
28     }
29 }
public class studentdemo {    //同上
    public static void main(string[] args) {
        //创建资源
        student s = new student();
        
        //设置和获取的类
        setthread st = new setthread(s);
        getthread gt = new getthread(s);

        //线程类
        thread t1 = new thread(st);
        thread t2 = new thread(gt);

        //启动线程
        t1.start();
        t2.start();
    }
}

 

厕所排队(使用信号量)

 1 import java.util.random;
 2 import java.util.concurrent.semaphore;
 3 
 4 class wc extends thread {
 5     private string name;
 6     private semaphore wc;
 7     
 8     public wc(string name, semaphore wc) {
 9         this.name = name;
10         this.wc = wc;
11     }
12     
13     @override
14     public void run() {
15         int availablepermit = wc.availablepermits();
16         if (availablepermit > 0) {
17             system.out.println(name+",好开心啊,我终于有坑了");
18         }else {
19             system.out.println(name+"怎么没有坑了。。。");
20         }
21         
22         try {
23             wc.acquire();
24             system.out.println(name+",好开心啊,我终于抢到了!");
25             thread.sleep(new random().nextint(1000));
26             system.out.println(name+",好爽啊,终于上完了!");
27             wc.release();
28         } catch (interruptedexception e) {
29 
30         }
31     }
32 }
33 
34 public class demo {
35     public static void main(string[] args) {
36         semaphore semaphore = new semaphore(3);
37         
38         for (int i = 0; i < 10; i++) {
39             wc wc = new wc("第"+i+"个人", semaphore);
40             wc.start();
41         }
42     }
43 }

 

the sleeping barber (生产者消费者,信号量)

 1 import java.util.concurrent.semaphore;
 2 
 3 public class barber implements runnable{
 4 
 5     semaphore customerwaiting, seats, barbersleeping;
 6     
 7     barber(semaphore customerwaiting, semaphore seats, semaphore barbersleeping) {
 8         this.customerwaiting = customerwaiting;
 9         this.seats = seats;
10         this.barbersleeping = barbersleeping;
11     }
12     
13     public void run() {
14         
15         while (true){
16             
17             // get a customer, sleep otherwise
18             try {
19                 customerwaiting.acquire();
20             } catch (interruptedexception e) {}
21 
22             // cut the hair of the customer    
23             system.out.println("cutting hair");
24             barbersleeping.release();            
25             
26         }
27     }
28 }
 1 import java.util.concurrent.semaphore;
 2 
 3 public class customer implements runnable{
 4 
 5     semaphore customerwaiting, seats, barbersleeping;
 6 
 7     boolean cut = false;
 8     customer(semaphore customerwaiting, semaphore seats, semaphore barbersleeping) {
 9         this.customerwaiting = customerwaiting;
10         this.seats = seats;
11         this.barbersleeping = barbersleeping;
12 
13     }
14     
15     public void run() {
16         while (!cut) {
17             
18             // a random delay
19             // don't want all the threads trying at once!
20             try {
21                 thread.sleep((long)(math.random()*100));
22             } catch (interruptedexception e1) {}
23             
24             // try to get a seat in the waiting room
25             try {
26                 seats.acquire();
27             } catch (interruptedexception e) {}
28             system.out.println(seats.availablepermits());
29 
30                 system.out.println(thread.currentthread().getname()+" is sitting down");
31                 // try and wake barber
32                 customerwaiting.release();
33 
34                 
35                 // get hair cut
36                 try {
37                     barbersleeping.acquire();
38                 } catch (interruptedexception e) {}
39                 cut = true;
40                 seats.release();
41             
42         }
43         system.out.println(thread.currentthread().getname()+" has had hair cut");        
44     }
45 }
 1 import java.util.concurrent.semaphore;
 2 
 3 public class runner {
 4 
 5     public static void main(string[] args) {
 6         
 7         semaphore barbersleeping = new semaphore(1);
 8         semaphore customerwaiting = new semaphore(1);
 9         try {
10             customerwaiting.acquire();
11             barbersleeping.acquire();
12         } catch (interruptedexception e) {
13         }
14         
15         semaphore seats = new semaphore(3);
16         
17         barber bar = new barber(customerwaiting,seats,barbersleeping);
18         thread bthread = new thread(bar);
19         bthread.start();
20         
21         int ncust = 30;
22         customer customers[] = new customer[ncust];
23         thread cthread[] = new thread[ncust];
24         
25         for (int i=0;i<ncust;i++) {
26              customers[i] = new customer(customerwaiting,seats,barbersleeping);
27              cthread[i] = new thread(customers[i]);
28              cthread[i].start();
29         }
30     }
31 }