参考的博客原文:
Java中的多线程你只要看这一篇就够了(墙裂推荐这个链接,治好了多年的隐疾)
- 最初场景:生产者消费者模式
模拟买票Ticket
package multiThread;
public class Ticket implements Runnable {
//共100票
int ticket = 100;
@Override
public void run() {
//模拟卖票
while (true) {
if (ticket > 0) {
//模拟选坐的操作
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖票:" + ticket--);
}
}
}
}
测试类ThreadDemo
package multiThread;
public class ThreadDemo {
public static void main(String[] args) {
//创建票对象
Ticket ticket = new Ticket();
//创建3个窗口s
Thread t1 = new Thread(ticket, "窗口1");
Thread t2 = new Thread(ticket, "窗口2");
Thread t3 = new Thread(ticket, "窗口3");
t1.start();
t2.start();
t3.start();
}
}
===进阶版本
package multiThread;
import java.util.LinkedList;
import java.util.Queue;
/**
*
* @author ziboris
* @date 2018年11月23日 上午9:15:43
*
*/
//1.queue的所有操作都会notifyAll 但是目前一定有一个线程触发这个notifyall
//其他线程因为还需要苏醒之后调度时间,肯定竞争不过他
//因此基本{产生满,同一个消费者消费完毕},{},{}....
//---》解决方案 在A出加上sleep代码块
public class ProducerConsumer {
public static class Producer extends Thread {// 生产者阻塞时候是判满
Queue<Integer> queue;
int maxSize;
public Producer(Queue<Integer> queue, int maxSize, String name) {
this.queue = queue;
this.maxSize = maxSize;
this.setName(name);
// TODO Auto-generated constructor stub
}
@Override
public void run() {
// TODO Auto-generated method stub
// LinkedBlockingQueue<Integer> bQueue=new LinkedBlockingQueue<>();
while (true) {
// A
try {
Thread.sleep(500L);
} catch (InterruptedException e) {
e.printStackTrace();
// TODO: handle exception
}
synchronized (queue) {
System.out.println(this.getName() + " is in lock");
if (queue.size() == maxSize) {
System.out.println("queue is full--" + this.getName() + "--so waiting");
try {
queue.wait();// wait在queue这个资源上面 保存一份阻塞时候的状态,到时候被唤醒的时候可以直接往下面运行
} catch (Exception e) {
// TODO: handle exception
}
}
int num = (int) (Math.random() * 100);
queue.offer(num);// offer在加满的时候会返回一个false put会一直等待知道出现空位 add会抛出异常
System.out.println(this.getName() + "-produce a ticket:-" + num);// 线程的子类可以用getname获取到初始化的name或者setname
queue.notifyAll();// 因为其他被阻塞的线程都等待在queue这个资源上面
System.out.println(" log out a produce");
}
}
}
}
public static class Consumer extends Thread {
Queue<Integer> queue;
int maxSize;
public Consumer(Queue<Integer> queue, int maxSize, String name) {
// TODO Auto-generated constructor stub
this.queue = queue;
this.maxSize = maxSize;
this.setName(name);
}
@Override
public void run() {
// TODO Auto-generated method stub
// super.run();
while (true) {
try {
Thread.sleep(200L);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
synchronized (queue) {
System.out.println(this.getName() + " is in lock");
if (queue.isEmpty()) {
System.out.println("queue is empty--" + this.getName() + "--so waiting");
try {
queue.wait();
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
int num = queue.poll();// queue的remove和poll都是去除第一个元素,空的时候一个是返回exception,null
System.out.println(this.getName() + "- consume a ticket-" + num);
queue.notifyAll();
System.out.println(this.getName() + " log out a consume");
}
}
}
}
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<>();
int maxSize = 10;
Producer producer = new Producer(queue, maxSize, "Producer");
Consumer consumer1 = new Consumer(queue, maxSize, "consumer1");
Consumer consumer2 = new Consumer(queue, maxSize, "consumer2");
Consumer consumer3 = new Consumer(queue, maxSize, "consumer3");
producer.start();
consumer1.start();
consumer2.start();
consumer3.start();
}
}
- 并发和并行
并行 | 多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时 |
---|---|
并发 | 通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。 |
-
线程状态与状态转换
-
join
下面程序如果不join:
—Main Thread is finished
Thread2 begins:Thu Nov 22 20:17:39 CST 2018
Thread1 begins:Thu Nov 22 20:17:39 CST 2018
Thread1 has finished: Thu Nov 22 20:17:44 CST 2018
Thread2 has finished: Thu Nov 22 20:17:44 CST 2018
发现main结束的时候两个子线程还没有启动好
加上join(1,2先后随机)
Thread2 begins:Thu Nov 22 20:20:02 CST 2018
Thread1 begins:Thu Nov 22 20:20:02 CST 2018
Thread2 has finished: Thu Nov 22 20:20:07 CST 2018
Thread1 has finished: Thu Nov 22 20:20:07 CST 2018
—Main Thread is finished
package multiThread;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class TestJoin implements Runnable {
private String name;
public TestJoin(String name) {
this.name = name;
}
public void run() {
System.out.printf("%s begins:%s\n", name, new Date());
try {
TimeUnit.SECONDS.sleep(5L);
} catch (InterruptedException e) {
e.printStackTrace();
// TODO: handle exception
}
System.out.printf("%s has finished: %s\n", name, new Date());
}
public static void main(String[] args) {
Thread thread1 = new Thread(new TestJoin("Thread1"));
Thread thread2 = new Thread(new TestJoin("Thread2"));
thread1.start();
thread2.start();
// try {
// thread1.join();
// thread2.join();
// } catch (InterruptedException e) {
// e.printStackTrace();
// // TODO: handle exception
// }
System.out.println("---Main Thread is finished");
}
}
- wait notify && notifyall
Causes the current thread to wait until another thread invokes
沉睡自己,知道其他线程唤醒自己 notify notifyall线程在运行的时候,如果发现某些条件没有被满足,可以调用wait方法暂停自己的执行,并且放弃已经获得的锁,然后进入等待状态。当该线程被其他线程唤醒并获得锁后,可以沿着之前暂停的地方继续向后执行,而不是再次从同步代码块开始的地方开始执行。但是需要注意的一点是,对线程等待的条件的判断要使用while而不是if来进行判断。这样在线程被唤醒后,会再次判断条件是否正真满足。
- 基本线程类 Thread类,Runnable接口,Callable接口
extends Thread还是implement runnable (二者基本类似 ,区别见下)
参考博文:java创建线程implement runnable 和 extends thread 比较
Thread(runnable):
//当前线程可转让cpu控制权,让别的就绪状态线程运行(切换)
public static Thread.yield()
//yield()的作用是让步。它能让当前线程由“运行状态”进入到“就绪状态”,大家再次同一起跑线竞争
//暂停一段时间
public static Thread.sleep()
//在一个线程中调用other.join(),将等待other执行完后才继续本线程。
public join()
//后两个函数皆可以被打断
public interrupte()
- synchronized wait notify notifyAll 是任何对象都具有的方法,因为任何对象都是一个资源
java中每一个对象都有一个monitor监视器,只在多线程的时候发挥作用
synchronized wait notify 必须是针对同一个对象资源
每一个对象的monitor有一个进入队列和等待队列(实质上多等待着占有这个资源)
- volatile 多线程之间实时看见这个变量
线程的创建的时候是将main线程内存load到自己的线程栈里面,完成run之后再save回去
volatile的作用是每一次的改变操作都会立马save回去 因此main中需要交给各个线程处理的变量要么是volatile 要么是final
- 高级多线层控制工具类:java.util.concurrent包里面since jdk1.5
ThreadLocal 为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量(如session)(墙裂推荐这个链接)
Atomic***(AtomicInteger AtomicBoolean)
Lock
容器类
管理类
【补充】
- 线程优先级:
Java线程可以有优先级的设定,高优先级的线程比低优先级的线程有更高的几率得到执行
优先级可以用从1到10的范围指定。10表示最高优先级,1表示最低优先级,5是普通优先级(default)
- 设置线程名字和线程组名字
看线程出问题 jstack -pid 使用trycatch不行
线程组,批量管理多个线程
- Thread.currentThread()与this的区别
参考资料:Thread.currentThread()与this的区别
this 在类里面如论如何都指向这个类
但是在这个自定义线程类中,只有run里面this和currentThread才相等