多线程看这一篇文章就够了

第一章 多线程概述

1
2
3
1. 什么是程序?
2. 什么是进程?
3. 什么是线程?
  • 程序
1
是为完成特定任务、用某种语言编写的一组指令的集合(一段静态的代码)
  • 进程
1
是程序的一次执行过程,或是正在运行的一个程序
  • 线程
1
2
3
进程可进一步细化为线程,是一个程序内部的一条执行路径

若一个程序可同一时间执行多个线程,我们称之为多线程.
  • 多线程的使用
1
2
3
4
5
我们在什么情况下使用多线程呢?

1. 程序需要同时执行多个任务的时候(2个或2个以上)
2. 程序需要实现一些需要等待的任务时(例如360杀毒软件中有很多功能,但是这些功能都没有被调用,都在等待被调)
3. 后台运行的程序

第二章 多线程创建和使用

1
2
3
Java线程创建有两种方式
1. 一种是继承Thread类
2. 一种是实现Runnable接口

第1节 继承Thread类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class TestDemo1 {

    public static void main(String[] args) {

        //创建线程
        MyThread mt = new MyThread();
        //启动线程
        mt.start();
    }

}

/**
 * 编写自定义类实现Thread类,重写run方法
 * run方法由jvm虚拟机调用,待抢到CPU资源之后才会执行
 */
class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("我被线程调用了...");
    }
}

第2节 实现Runnable接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class TestDemo2 {
    public static void main(String[] args) {
        //创建MyRunnable实例
        MyRunnable mr = new MyRunnable();
        //创建线程
        Thread t = new Thread(mr);
        //启动
        t.start();
    }
}
class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println("我被线程调用了...");
    }
}

第三章 线程的优先级

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* Thread类中自带优先级设置 最小优先级
*/
public final static int MIN_PRIORITY = 1;

/**
* Thread类中自带优先级设置 默认优先级
*/
public final static int NORM_PRIORITY = 5;

/**
* Thread类中自带优先级设置 最大优先级
*/
public final static int MAX_PRIORITY = 10;
1
2
3
4
5
6
Thread类中提供了设置和获取优先级的方法

setPriority(): 设置优先级(取值范围1-10)
getPriority(): 获取优先级方法

在线程中设置线程优先级不会出现明显的变化,优先级高的话只是分配到CPU资源的概率高.

第四章 Thread类常用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
start():线程启动方法
run(): 线程被调度时执行的方法
getName(): 返回线程名称
setName(String name): 设置线程名称
currentThread(): 返回当前线程
yield(): 线程让步
	暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程
	若队列中没有同优先级的线程,忽略此方法
	线程让步,不代表暂停执行,就像你在高速开车,让了路,不代表车停下来,让给其他线程,CPU可能还会分配给它资源.
join():当某个程序执行中调用其他线程的join()方法时,调用线程将被阻塞,直到join()方法加入的join线程执行完为止.低优先级的线程也可以获得执行
sleep(long millis): 令当前活动线程在指定时间段内放弃对CPU控制,使其他线程有机会被执行,时间到后重排队
stop(): 强制线程生命期结束(已过时)
isAlive(): 返回boolean,判断线程是否还活着
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//join测试

public class TestDemo01 {
    public static void main(String[] args) throws InterruptedException {
        TaskRnnable t = new TaskRnnable();
        Thread t1 = new Thread(t, "线程1");
        Thread t2 = new Thread(t, "线程2");
        t1.start();
        t1.join();//join之后必须t1结束之后才能执行t2
        t2.start();
    }
}

class TaskRnnable implements Runnable{
    @Override
    public void run() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"执行了....");
    }
}

第五章 线程的生命周期

1
线程的生命周期状态: 创建 -- 就绪 -- 运行 -- 停止 -- 阻塞

 

第六章 线程同步

1
2
3
4
5
6
7
8
9
因为多线程执行的不确定性引起执行结果的不稳定性,可能造成数据出现问题.

Java中引入互斥锁的概念,来保证共享数据操作的完整性.每个对象都对应于一个可称为"互斥锁" 的标记;这个标记用来保证在任一时刻,只能有一个线程访问该对象.

在Java中使用synchronized关键字来实现互斥锁
1. 同步代码块
	锁对象: 1.1 实例对象(锁实例数据)  1.2 静态对象(锁静态数据)
2. 同步方法
	2.1 实例方法(锁为this)  2.2 静态方法(锁为当前类本身)

模拟火车站售票程序,开启三个窗口售票

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//通过这个案例,多次执行会发现他的数据执行顺序是有问题的.
public class TestDemo3 {
    public static void main(String[] args) {
        //创建车票
        Ticket ticket = new Ticket();
        //创建线程并启动
        new Thread(ticket,"win1").start();
        new Thread(ticket,"win2").start();
        new Thread(ticket,"win3").start();
    }
}
class Ticket implements Runnable{
    private int ticket=100;
    @Override
    public void run() {
        while(true){
            if(ticket>0){
                System.out.println("窗口-> "+ Thread.currentThread().getName() +" <- 买票"+ticket+"剩余票数为:"+ --ticket);
            }else {
                break;
            }
        }
    }
}

解决问题

  • 同步代码块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
synchronized (锁对象){
	//需要锁定的资源
}

public class TestDemo3 {
    public static void main(String[] args) {
        //创建车票
        Ticket ticket = new Ticket();
        //创建线程并启动
        new Thread(ticket,"win1").start();
        new Thread(ticket,"win2").start();
        new Thread(ticket,"win3").start();
    }
}
class Ticket implements Runnable{

    private int ticket=100;

    @Override
    public void run() {
        while(true){
          	//锁定共享资源
            synchronized (this){
                if(ticket>0){
                    System.out.println("窗口-> "+ Thread.currentThread().getName() +" <- 买票"+ticket+"剩余票数为:"+ --ticket);
                }else {
                    break;
                }
            }
        }
    }
}
  • 同步方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//使用synchronized修饰操作共享资源的方法

public class TestDemo4 {
    public static void main(String[] args) {
        //创建车票
        Ticket1 ticket = new Ticket1();
        //创建线程并启动
        new Thread(ticket,"win1").start();
        new Thread(ticket,"win2").start();
        new Thread(ticket,"win3").start();
    }
}
class Ticket1 implements Runnable{
    private int ticket=100;
    @Override
    public void run() {
        while(true){
            sale();
        }
    }
  	//给操作共享资源的方法添加synchronized
    public synchronized void sale(){
        if(ticket>0){
            System.out.println("窗口-> "+ Thread.currentThread().getName() +" <- 买票"+ticket+"剩余票数为:"+ --ticket);
        }else{
            return;
        }
    }
}

第七章 死锁

1
不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
public class DeadLock implements Runnable {
	private static Object obj1 = new Object();
	private static Object obj2 = new Object();
	private boolean flag;
	public DeadLock(boolean flag) {
		this.flag = flag;
	}
	@Override
	public void run() {	
		if(flag) {
			synchronized (obj1) {
				System.out.println(Thread.currentThread().getName()+"已经锁定obj1");
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				//如果出现死锁当前执行不到
				synchronized (obj2) {
					System.out.println("一秒钟后"+Thread.currentThread().getName()+"已经锁定obj2");
				}
			}
		}else {
			synchronized (obj2) {
				System.out.println(Thread.currentThread().getName()+"已经锁定obj2");
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				//如果死锁访问不到
				synchronized (obj1) {
					System.out.println("一秒钟后"+Thread.currentThread().getName()+"已经锁定obj1");
				}
			}
		}		
	}
}

//main方法
/**
 * 死锁
 *
 * obj1
 * obj2
 * 
 * A线程
 * run(){
 * 	synchronized(obj1){
 * 		//代码
 * 		synchronized(obj2){
 * 			//
 * 		}	
 * 	}
 * }
 * B线程
 * run(){
 * 	synchronized(obj2){
 * 		//代码
 * 		synchronized(obj1){
 * 			//
 * 		}	
 * 	}
 * }
 */
public class TestDemo01 {
	public static void main(String[] args) {
		//new Thread(new DeadLock(true)).start();
		new Thread(new DeadLock(false)).start();//死锁
		new Thread(new DeadLock(true)).start();
	}
}

第八章 线程通信

第1节 为什么要进行线程通信

多个线程并发执行时,在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成一件任务.并且我们希望他们有规律的执行,那么多线程之间需要一些协调通信

第2节 Java语言实现通信的方式

java.lang.Object类中提供了wait()/notify/notifyAll()方法实现线程之间的通信;这三个方法必须在synchronized方法或synchronized代码块中才能使用,否则会报java.lang.IllegalMonitorStateException异常
  • wait()方法
当前线程挂起并放弃CPU,释放对锁的拥有权(在wait时必须先获取锁,所以wait必须在synchronized中),同时在等待的位置加一个标志,以备后面被唤醒时它好能从标志位置获得锁的拥有权,变成就绪状态.
  • notify()方法
1
唤醒一个等待当前对象的锁的线程
  • notifyAll()方法
1
方法会唤醒在此对象监视器上等待的所有线程

第3节 练习(使用两个线程打印 1-100 线程1, 线程2 交替打印)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class PrintNum implements Runnable{
	int num=1;
	@Override
	public void run() {
		while(true) {
			synchronized (this) {
				notify();//唤醒
				try {
					Thread.sleep(100);
				} catch (InterruptedException e1) {
					e1.printStackTrace();
				}
				if(num<=100) {
					System.out.println(Thread.currentThread().getName()+"-->"+ num);
					num++;
					try {
						//等待
						wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}			
				}else {
					break;
				}
			}
		}
	}
}

public static void main(String[] args) {
		/*
		 * 创建两个线程,循环1-100
		 */
		PrintNum p = new PrintNum();
		new Thread(p).start();
		new Thread(p).start();
	}

第九章 生产着消费者模式

  • 容器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class Box {
	//设置盒子容量
	private int c=0; //最大值10
	/**
	 * 向盒子中添加对象
	 */
	public synchronized void add() {
		if(c>=10) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}else {
			System.out.println("生产产品"+c);
			c++;
			notifyAll();
		}
	}
	/**
	 * 获取
	 */
	public synchronized void get() {
		if(c<=0) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}else {
			System.out.println("消费产品"+c);
			c--;
			notifyAll();
		}	
	}	
}
  • 生产者
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * 生产线程
 */
public class Pro implements Runnable{
	Box box;
	public Pro(Box box) {
		this.box = box;
	}
	@Override
	public void run() {
		System.out.println("生产开始....");
		while(true) {
			try {
				Thread.sleep((int)Math.random()*1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}		
			box.add();
		}
	}
}
  • 消费者
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
 * 消费线程
 */
public class Cus implements Runnable {
	Box box;
	public Cus(Box box) {
		this.box = box;
	}
	@Override
	public void run() {
		System.out.println("消费开始...");
		while(true) {
			try {
				Thread.sleep((int)Math.random()*1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}		
			box.get();
		}
	}
}
  • 测试
1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) {
		//创建容器	
		Box box = new Box();
		//创建生产者
		Pro pro = new Pro(box);
  	//创建消费者
		Cus cus = new Cus(box);
		//给生产者分配线程
		new Thread(pro).start();
  	//给消费者分配线程
		new Thread(cus).start();
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT枫斗者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值