多线程

1. 操作系统

  操作系统是控制计算机的操作运行和硬件软件资源的系统软件程序,用于提供公共服务来组织用户交互。

  操作系统根据运行环境,可以分为桌面操作系统、手机操作系统、服务器操作系统、嵌入式操作系统等等

2. 进程

  进程是计算机中程序关于某数据集合上的一次运行活动,是系统进行资源分配的基本单位,是操作系统结构的基础。

3. 线程

  线程是操作系统进行运算调度的最小单位,包含在进程之中,是进程中的实际运作单位。

4. 线程的三种实现方式和线程池

  (1).自定义Thread类型,重写run()方法

 1 public class ThreadDemo01 {
 2     public static void main(String[] args) {
 3         Thread t1 = new ThreadDemo02();
 4         ThreadDemo02 t2 = new ThreadDemo02();
 5         Thread t3 = new Thread(t2);
 6         Thread t4 = new Thread(){
 7             @Override
 8             public void run() {
 9                 for (int i = 0; i < 10000; i++) {
10                     System.out.print(Thread.currentThread().getName() + " ");
11                     System.out.println(i);
12                 }
13             }
14         };
15         t1.start();
16         t2.start();
17         t3.start();
18         t4.start();
19     }
20 }
1 public class ThreadDemo02 extends Thread {
2     @Override
3     public void run() {
4         for (int i = 0; i < 10000; i++) {
5             System.out.print(Thread.currentThread().getName() + " ");
6             System.out.println(i);
7         }
8     }
9  

  (2).自定义类实现Callable接口,重写call()方法,FutureTask

 1 public class ThreadDemo03 implements Callable {
 2     public static void main(String[] args) throws Exception{
 3         ThreadDemo03 t1 = new ThreadDemo03();
 4         FutureTask ft = new FutureTask(t1);
 5         new Thread(ft).start();
 6         System.out.println(ft.get());
 7     }
 8     public String call() throws Exception {
 9         Thread.sleep(1000);
10         return "hello";
11     };
12 }

  (3).自定义类实现Runnable接口,重写run()方法

 1 public class ThreadDemo04 implements Runnable{
 2     public static void main(String[] args){
 3         ThreadDemo04 t1 = new ThreadDemo04();
 4         new Thread(t1).start();
 5 
 6         for(int i = 0;i<100;i++){
 7             System.out.println("这是main方法 "+i);
 8         }
 9     }
10     @Override
11     public void run() {
12         for(int i = 0;i<10;i++){
13             System.out.println("这是run方法 "+i);
14         }
15     }
16 }

  (4). 线程池

 1 public class ThreadPoolExecutorDemo {
 2     public static void main(String[] args) {
 3         /*
 4          * int corePoolSize 核心线程数
 5          * int maximumPoolSize 最大线程数
 6          * long keepAliveTime 有效时间
 7          * TimeUnit unit 时间单位
 8          * BlockingQueue<Runnable> workQueue 队列
 9          * RejectedExecutionHandler handler 拒绝策略
10          **/
11 
12         ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10,
13                 20,
14                 30,
15                 TimeUnit.SECONDS,
16                 new ArrayBlockingQueue<>(5));
17         for(int i = 0; i < 30; i++){
18             poolExecutor.submit(new Runnable(){
19                 @Override
20                 public void run(){
21                     for(int i = 0 ; i < 10; i++){
22                         System.out.println(Thread.currentThread().getName() + ", " + i);
23                     }
24                 }
25             });
26         }
27     }
28 }

拒绝策略:

5. 线程状态

6. 线程安全

  线程安全(Thread-Safe)是指在多线程环境下,对共享资源的访问不会导致不正确的结果。在并发编程中,多个线程同时访问共享资源可能会导致数据竞争(Data Race)和死锁(Deadlock)等问题,因此保证线程安全是非常重要的。

  一个线程安全的程序,不仅在单线程环境下能够正确地执行,而且在多线程环境下也能够正确地执行。为了保证线程安全,程序需要采取一些同步措施,例如使用线程锁(Thread Lock)、原子操作(Atomic Operation)、线程安全的数据结构等。

7. 线程锁

  线程锁是一种同步机制,用于协调多个线程之间对共享资源的访问。在并发编程中,多个线程可以同时访问共享资源,但同时进行的读写操作可能会导致数据不一致的情况发生。线程锁的作用就是确保在任何时刻只有一个线程可以访问共享资源,从而避免数据竞争和死锁等并发编程中常见的问题。

  线程锁的基本原理是,在多个线程竞争访问同一共享资源的时候,只有一个线程能够获取到锁,其他线程需要等待锁被释放后才能进入临界区执行相应的操作。一旦线程完成了对共享资源的访问,它就会释放锁,让其他线程能够获取到锁并访问共享资源。

  (1). synchronized同步代码块

 1 public class Main {
 2     public static void main(String[] args) {
 3         MyThread myThread = new MyThread();
 4         Thread t1 = new Thread(myThread);
 5         Thread t2 = new Thread(myThread);
 6         t1.start();
 7         t2.start();
 8 
 9     }
10 }
 1 public class MyThread extends Thread{
 2     public int num = 100;
 3     public Object obj = new Object();
 4     @Override
 5     public void run() {
 6         while(true) {
 7             synchronized(obj) {
 8                 if(this.num > 0) {
 9                     try {
10                         Thread.sleep(50);
11                     } catch (Exception e) {
12                         e.printStackTrace();
13                     }
14                     System.out.println(Thread.currentThread().getName() + ": " + num--);
15                 } else {
16                     break;
17                 }
18             }
19         }
20     }
21 }

  (2). synchronized同步方法

 1 public class Main {
 2     public static void main(String[] args) {
 3         MyThread myThread = new MyThread();
 4         Thread t1 = new Thread(myThread);
 5         Thread t2 = new Thread(myThread);
 6         t1.start();
 7         t2.start();
 8 
 9     }
10 }
 1 public class MyThread extends Thread{
 2     public int num = 100;
 3     public boolean flag = false;
 4     @Override
 5     public void run() {
 6         while (!flag) {
 7             sale();
 8         }
 9     }
10 
11     public synchronized void sale() {
12         if (this.num > 0) {
13             try {
14                 Thread.sleep(50);
15             } catch (Exception e) {
16                 e.printStackTrace();
17             }
18             System.out.println(Thread.currentThread().getName() + ": " + num--);
19         } else {
20             flag = true;
21         }
22     }
23 }

   (3). Lock锁

 1 import java.util.concurrent.locks.ReentrantLock;
 2 
 3 public class LockDemo implements Runnable{
 4     public ReentrantLock lock = new ReentrantLock();
 5     public int num = 100;
 6     @Override
 7     public void run() {
 8         while (true) {
 9             lock.lock();
10             if (this.num > 0) {
11                 try {
12                     Thread.sleep(50);
13                 } catch (Exception e) {
14                     e.printStackTrace();
15                 }
16                 System.out.println(Thread.currentThread().getName() + ": " + num--);
17             } else {
18                 break;
19             }
20             lock.unlock();
21         }
22     }
23 
24     public static void main(String[] args) {
25         LockDemo l1 = new LockDemo();
26         Thread t1 = new Thread(l1);
27         Thread t2 = new Thread(l1);
28         t1.start();
29         t2.start();
30     }
31 }

  (4).加锁对于对象的影响(JOL查看对象的内存情况)

 1 import org.openjdk.jol.info.ClassLayout;
 2 
 3 public class Student {
 4     public static void main(String[] args) {
 5         Student st = new Student();
 6         st.age = 20;
 7         st.name = "ZhangSan";
 8         System.out.println(ClassLayout.parseInstance(st).toPrintable());
 9         System.out.println("============================");
10         synchronized (st) {
11             System.out.println(ClassLayout.parseInstance(st).toPrintable());
12         }
13 
14     }
15     public int age;
16     public String name;
17 }

结果:在对象的标记处做了修改

Demo14.Student object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000005 (biasable; age: 0)
8 4 (object header: class) 0x2000ce08
12 4 int Student.age 20
16 4 java.lang.String Student.name (object)
20 4 (object alignment gap)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

============================
Demo14.Student object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000022e1671d005 (biased: 0x000000008b859c74; epoch: 0; age: 0)
8 4 (object header: class) 0x2000ce08
12 4 int Student.age 20
16 4 java.lang.String Student.name (object)
20 4 (object alignment gap)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

 

 

锁一共有4种状态,级别从低到高依次是:无锁、偏向锁、轻量级锁和重量级锁,锁状态只能升级不能降级

 8. wait和notify

wait() --- 阻塞; notify() --- 释放

 1 public class WaitDemo {
 2     public static Object obj1 = new Object();
 3     public static void main(String[] args) throws Exception{
 4         new Thread(() -> {
 5             synchronized(obj1) {
 6                 System.out.println(Thread.currentThread().getName() + ": A");
 7                 try {
 8                     obj1.wait();
 9                 } catch (InterruptedException e) {}
10                 System.out.println(Thread.currentThread().getName() + ": B");
11             }
12         }).start();
13 
14         Thread.sleep(1000);
15         synchronized(obj1) {
16             obj1.notify();
17             System.out.println(Thread.currentThread().getName() + ": C");
18         }
19     }
20 }

9. LockSupport

part() --- 阻塞; unpart() --- 释放

 1 public class LockSupportDemo {
 2     public static void main(String[] args) throws InterruptedException{
 3         Thread t0 = new Thread(new Runnable() {
 4             @Override
 5             public void run() {
 6                 System.out.println(Thread.currentThread().getName() + ": A");
 7                 LockSupport.park(); //阻塞
 8                 System.out.println(Thread.currentThread().getName() + ": B");
 9             }
10         });
11         t0.start();
12         Thread.sleep(1000);
13         System.out.println(Thread.currentThread().getName() + ": C");
14         LockSupport.unpark(t0);
15 
16     }
17 }

10. Join

 join() --- 等待该线程终止(先让此线程运行至终止)

 1 public class JoinDemo extends Thread{
 2     @Override
 3     public void run() {
 4         for (int i = 0; i < 10; i++) {
 5             System.out.println(Thread.currentThread().getName() + ": " + i);
 6         }
 7     }
 8 
 9     public static void main(String[] args) throws InterruptedException {
10         JoinDemo j1 = new JoinDemo();
11         j1.start();
12         j1.join(); //等待该线程终止
13         for (int i = 0; i < 10; i++) {
14             System.out.println(Thread.currentThread().getName() + ": " + i);
15         }
16     }
17 }

11. Daemon

当所有线程都是Daemon守护线程时,jvm会自动终止

 1 import java.io.IOException;
 2 
 3 public class DaemonDemo extends Thread {
 4     @Override
 5     public void run() {
 6         for (int i = 0; i < 10; i++) {
 7             try {
 8                 Thread.sleep(2000);
 9             } catch (InterruptedException e) {
10                 e.printStackTrace();
11             }
12             System.out.println(Thread.currentThread().getName() + ": " + i);
13         }
14     }
15 
16     public static void main(String[] args) throws InterruptedException, IOException {
17         DaemonDemo d1 = new DaemonDemo();
18         d1.setDaemon(true);
19         d1.start();
20 
21         System.in.read(); //阻塞, 等待用户输入
22     }
23 }

 12. ThreadLocal --- 线程局部变量

 1 public class ThreadLocalDemo {
 2     public static ThreadLocal<Integer> local = new InheritableThreadLocal<>(){
 3         @Override
 4         protected Integer initialValue() {
 5             return 0;
 6         }
 7     };
 8 
 9     public static void main(String[] args) {
10         new Thread(() -> {
11             for (int i = 0; i < 3; i++) {
12                 local.set(local.get()+ 1);
13             }
14             System.out.println(Thread.currentThread().getName()+ ": " + local.get());
15         }).start();
16 
17         new Thread(() -> {
18             for (int i = 0; i < 3; i++) {
19                 local.set(local.get()+ 1);
20             }
21             System.out.println(Thread.currentThread().getName()+ ": " + local.get());
22         }).start();
23     }
24 }

结果: 由于变量是局部变量,所以结果不是一个3一个4,而是两个都是3

  Thread-1: 3
  Thread-0: 3

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

posted @ 2023-03-15 16:34  JiuXis  阅读(42)  评论(0)    收藏  举报