多线程
进程 :是执行程序的一次执行过程,他是一个动态的概念.
线程 : 通常一个金层可以包饭多个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程是cpu调度和执行的单位
很多多线程是模拟出来的,真的的多线程是指有多个cpu,即多核,如服务器。
核心概念
1.线程就是独立的执行路径
2.在程序运行时,即使没有自己创建的线程,后台也会有多个线程,如主线程,gc线程
3.main()称之为主线程,为系统的入口,用于执行整个程序
4.在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为人为干预的
5.对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制
6.线程会带来额外的开销,如cpu调度时间,并发控制开销
7.每个线程在自己的工作内存交互,内存控制不当会造成数据不一致
线程创建
1.继承Thred
2.实现Runable接口
3.实现Callable接口(了解)
package syn;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
//回顾线程池的创建
public class ThreadNew {
public static void main(String[] args) {
new Thread01().start();
new Thread(new Thread02()).start();
FutureTask<Integer> task = new FutureTask<Integer>(new Thread03());
new Thread(task).start();
try {
Integer integer = task.get();
System.out.println(integer);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
}
}
//1.继承Thread类
class Thread01 extends Thread {
@Override
public void run() {
System.out.println("继承Thread类");
}
}
//2.实现Runable接口
class Thread02 implements Runnable {
@Override
public void run() {
System.out.println("实现Runnable接口");
}
}
//3.实现Callable接口
class Thread03 implements Callable {
@Override
public Integer call() throws Exception {
System.out.println("继承Callable类");
return 100;
}
}
线程状态
package thread;
//观察测试线程的状态
public class TestState {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("/");
});
//观察状态
Thread.State state = thread.getState();
System.out.println(state); //NEW
//观察启动后
thread.start();
state=thread.getState();
System.out.println(state);
while (state!=Thread.State.TERMINATED){//只要线程不终止,就一直输出状态
Thread.sleep(1000);
state=thread.getState();
System.out.println(state);
}
//死亡之后不能启动
// thread.start();
}
}
Thread
不建议使用: 避免oop单继承局限性
package thread;
//总结 :注意,线程开启不一定立即执行,由cpu调度执行
public class TestThread01 extends Thread{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("我在看代码--"+i);
}
}
public static void main(String[] args) {
//main,主线程
//创建一个线程对象
TestThread01 thread01 = new TestThread01();
//调用start()开启线程
thread01.start();
for (int i = 0; i < 200; i++) {
System.out.println("我在学习多线程 --"+i);
}
}
}
package thread;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class TestThread02 extends Thread{
private String url;
private String name;
//构造器
public TestThread02(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public void run() {
WebDownLoader loader = new WebDownLoader();
loader.downLoader(url,name);
System.out.println("下载的文件名为 :"+name);
}
public static void main(String[] args) {
TestThread02 thread01 = new TestThread02("https://img1.baidu.com/it/u=3384796346,381674655&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500",
"1.jpg");
TestThread02 thread02 = new TestThread02("https://img0.baidu.com/it/u=530426417,2082848644&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500",
"2.jpg");
thread01.start();
thread02.start();
}
//下载器
class WebDownLoader{
public void downLoader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
}
Runnable
推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
package thread;
//创建线程方式2:实现runable接口,重写run方法,执行线程需要丢入runable接口实现类,调用start方法
public class TestThread03 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("我在看代码--"+i);
}
}
public static void main(String[] args) {
TestThread03 testThread03 = new TestThread03();
Thread thread = new Thread(testThread03);
thread.start();
for (int i = 0; i < 200; i++) {
System.out.println("我在学习多线程 --"+i);
}
}
}
买火车票和龟兔赛跑
package thread;
//买火车票的例子
//多个线程操作同一个资源的情况下,线程不安全,数据紊乱
public class TestThread04 implements Runnable{
private int ticketNums =10;
@Override
public void run() {
while (true){
if(ticketNums<=0){
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNums--+"票");
}
}
public static void main(String[] args) {
TestThread04 thread04 = new TestThread04();
new Thread(thread04,"小明").start();
new Thread(thread04,"小王").start();
new Thread(thread04,"小红").start();
}
}
package thread;
/**
* 龟兔赛跑
*/
public class TestThread05 implements Runnable {
private static String winner;
@Override
public void run() {
for (int i = 0; i <=100; i++) {
if("兔子".equals(Thread.currentThread().getName())&&i%10==0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
boolean falg=gameOver(i);
if(falg){
break;
}
System.out.println(Thread.currentThread().getName() + "-->跑了" + i + "步");
}
}
private boolean gameOver(int steps) {
if (winner != null) {
return true;
}
if (steps == 100) {
winner = Thread.currentThread().getName();
System.out.println("winner is" + winner);
}
return false;
}
public static void main(String[] args) {
TestThread05 thread05 = new TestThread05();
new Thread(thread05,"乌龟").start();
new Thread(thread05,"兔子").start();
}
}
Callable
package thread;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
//实现callable接口
/**
* 1.可以定义返回值
* 2.可以抛出异常
*
*/
public class TestThread06 implements Callable {
@Override
public Object call() throws Exception {
TestThread06.WebDownLoader loader = new TestThread06.WebDownLoader();
loader.downLoader(url,name);
System.out.println("下载的文件名为 :"+name);
return true;
}
private String url;
private String name;
//构造器
public TestThread06(String url, String name) {
this.url = url;
this.name = name;
}
public static void main(String[] args) {
TestThread06 thread01 = new TestThread06("https://img1.baidu.com/it/u=3384796346,381674655&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500",
"1.jpg");
TestThread06 thread02 = new TestThread06("https://img0.baidu.com/it/u=530426417,2082848644&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500",
"2.jpg");
//创建执行服务
// ExecutorService pool = Executors.newFixedThreadPool(3);
ThreadPoolExecutor pool = new ThreadPoolExecutor(3,3,
0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
//提交执行
Future r1 = pool.submit(thread01);
Future r2 = pool.submit(thread02);
//关闭服务
pool.shutdownNow();
}
//下载器
class WebDownLoader{
public void downLoader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
}
静态代理模式
package thread;
/**
* 1.静态代理模式总结:
* 2.真实对象和代理对象都要实现同一个接口
* 3.代理对象要代理真实角色
* <p>
* //好处:
* 1.代理对象可以做很多真实对象做不了的事情
* 2.真实对象专注做自己的事情
*/
public class StaticProxy {
public static void main(String[] args) {
// new Thread(new Runnable() {
// @Override
// public void run() {
// System.out.println("我爱你");
// }
// }).start();
new Thread(()->System.out.println("我爱你")).start();
new WeddingCompany(new You()).HappyMarry();
}
}
interface Marry {
//人间四大喜事
//久旱逢甘霖
//他乡遇故知
void HappyMarry();
}
//真实角色
class You implements Marry {
@Override
public void HappyMarry() {
System.out.println("秦老师要结婚了,超开心");
}
}
//代理角色,帮助你结婚
class WeddingCompany implements Marry {
//真实的角色
private Marry target;
public WeddingCompany(Marry target) {
this.target = target;
}
@Override
public void HappyMarry() {
before();
this.target.HappyMarry();
after();
}
private void before() {
System.out.println("结婚之前,布置现场");
}
private void after() {
System.out.println("结婚之后,收尾款");
}
}
线程停止-stop
package thread;
/**
* 线程的状态:
* 创建状态->就绪状态->(阻塞状态)->运行状态->死亡状态
*
*
*
*/
//停止线程
//1.建议线程正常停止---->利用次数
//2.建议使用标志位
//3.不要使用stop或者destroy等过时方法或者jdk不建议使用的方法
public class TestThread07 implements Runnable{
//设置一个标识位
private boolean flag =true;
@Override
public void run() {
int i=0;
while (flag){
System.out.println("run ......Thread"+i++);
}
}
//设置一个公开的方法停止线程
public void stop(){
this.flag=false;
}
public static void main(String[] args) {
TestThread07 thread07 = new TestThread07();
new Thread(thread07).start();
for (int i = 0; i < 1000; i++) {
System.out.println("main "+i);
if(i==900){
//调用stop方法切换标识位,让线程停止
thread07.stop();
System.out.println("该线程停止了 ");
}
}
}
}
线程休眠-sleep
package thread;
//模拟网络延迟:放大问题的发生性
public class TsetSleep1 implements Runnable{
private int ticketNums =10;
@Override
public void run() {
while (true){
if(ticketNums<=0){
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNums--+"票");
}
}
public static void main(String[] args) {
TsetSleep1 thread04 = new TsetSleep1();
new Thread(thread04,"小明").start();
new Thread(thread04,"小王").start();
new Thread(thread04,"小红").start();
}
}
线程礼让-yield
package thread;
/**
* 线程礼让,让当签证在执行的线程暂停,但不阻塞
* 将线程从运行状态转为就绪状态
*
* 让cpu重新调度,礼让不一定成功
*/
public class TestYield {
public static void main(String[] args) {
MyYield yield = new MyYield();
new Thread(yield,"a").start();
new Thread(yield,"b").start();
}
static class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程开始执行");
Thread.yield(); //礼让
System.out.println(Thread.currentThread().getName()+"线程停止执行");
}
}
}
线程强制执行-join
package thread;
//join方法
public class TestJoin implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("线程vip来了"+ i);
}
}
public static void main(String[] args) throws InterruptedException {
TestJoin testJoin = new TestJoin();
Thread thread = new Thread(testJoin);
thread.start();
for (int i = 0; i < 500; i++) {
if(i==200){
thread.join();
}
System.out.println("mian" +i);
}
}
}
线程优先级
java 提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度
器按照优先级决定应该调度哪个线程来执行
线程的优先级用数字来表示,范围时1-10
Thread.MIN_PRIORITY=1
Thread.MAX_PRIORITY =10
Thread.NORM_PRIORITY=5
使用一下方式改变或获取优先级
1.getPriority().setPriority(int xxx)
package thread;
//测试线程优先级
/**
* mac 及linux系统优先级无效
*
*
*/
public class TestPriority {
}
class MyPriority implements Runnable{
public static void main(String[] args) {
//主线程的默认优先级
System.out.println(Thread.currentThread().getName()+"--->"+
Thread.currentThread().getPriority());
MyPriority priority = new MyPriority();
Thread thread1 = new Thread(priority);
Thread thread2 = new Thread(priority);
Thread thread3 = new Thread(priority);
Thread thread4 = new Thread(priority);
Thread thread5 = new Thread(priority);
//设置优先级,在启动
thread1.start();
thread2.setPriority(1);
thread2.start();
thread4.setPriority(Thread.MAX_PRIORITY);
thread4.start();
thread5.setPriority(8);
thread5.start();
thread3.setPriority(4);
thread3.start();
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"--->"+
Thread.currentThread().getPriority());
}
}
守护线程
1.线程分为用户线程和守护线程
2.虚拟机必须确保用户线程执行完毕
3.虚拟机不用等待守护线程执行完毕
4.如,后台操作日志,监控内存,垃圾回收等待…
package thread;
//守护线程
public class TestDeamon {
public static void main(String[] args) {
God god = new God();
Yous yous = new Yous();
Thread thread =new Thread(god);
thread.setDaemon(true); //默认是false表示是用户线程,正常线程都是用户线程
thread.start();// 上帝线程守护启动
new Thread(yous).start();
}
}
class God implements Runnable{
@Override
public void run() {
while (true){
System.out.println("上帝保佑着你");
}
}
}
class Yous implements Runnable{
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("你一生都开心的活着");
}
System.out.println("======goodbye!world!======");
}
}
线程同步
并发 :多个线程同时操作一个对象
synchronized
1.一个线程持有锁会导致其他所有需要此锁的线程挂起
2.再多线程竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时,引起性能问题
3.如果一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题
同步方法
synchronizaed方法控制"对象"的访问,每个对象对应一把锁,每个synchronizaed方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一代执行,就独占该锁,知道该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行
方法里面需要修改的内容才需要锁,锁的太多,会造成资源浪费
package syn;
//不安全的买票
public class UnsafeBuyTicket {
}
//线程不安全
class BuyTicket implements Runnable {
public static void main(String[] args) {
BuyTicket ticket = new BuyTicket();
new Thread(ticket,"苦逼的我").start();
new Thread(ticket,"牛逼的你们").start();
new Thread(ticket,"可恶的黄牛党").start();
}
private int ticketNums = 10;
boolean flag = true;
@Override
public void run() {
//买票
while (flag) {
buy();
}
}
//同步方法,锁的是this
private synchronized void buy() {
if (ticketNums < 0) {
flag = false;
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//买票
System.out.println(Thread.currentThread().getName() + "拿到" + ticketNums--);
}
}
同步块
obj称之为同步监视器
1.第一个线程访问,锁定同步监视器,执行其中代码
2.第二个线程访问,发现同步监视器被锁定,无法访问
3.第一个线程访问完毕,解锁同步监视器
4.第二个线程访问,发现同步监视器没有锁,然后锁定并访问
package syn;
import oop.demo05.A;
//不安全的取钱
//两个人去银行取钱
public class UnsafeBank {
}
//账户
class Account{
int money; //余额
String name; //卡名
public Account(int money, String name) {
this.money = money;
this.name = name;
}
}
//银行
class Drawing extends Thread{
public static void main(String[] args) {
Account account1 = new Account(1000, "结婚基金");
Drawing you = new Drawing(account1, 50, "你");
Drawing girl = new Drawing(account1, 100, "girl");
you.start();
girl.start();
}
Account account;//账户
//取了多少钱
int drawingMoney;
int nowMoney;
public Drawing(Account account,int drawingMoney,String name){
super(name);
this.account=account;
this.drawingMoney=drawingMoney;
}
//取钱
@Override
public void run() {
//同步
//锁的对象就是变化的量,需要赠增删改的对象
synchronized (account){
if(account.money-drawingMoney<0){
System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
return;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//卡内余额
account.money=account.money-drawingMoney;
nowMoney=nowMoney+drawingMoney;
System.out.println(account.name+"余额"+account.money);
System.out.println(this.getName()+"手里的钱"+nowMoney);
}
}
}
package syn;
import java.util.ArrayList;
/**
* 线程不安全的集合 ArrayList
*
*
*/
public class UnsafeList {
public static void main(String[] args) {
ArrayList<String> strings = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
new Thread(()->{
synchronized (strings){
strings.add(Thread.currentThread().getName());
}
}).start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(strings.size());
}
}
JUC类(扩展)
package syn;
import java.util.concurrent.CopyOnWriteArrayList;
//测试JUC安全类型的集合
public class TestJUC {
public static void main(String[] args) {
CopyOnWriteArrayList<String> arrayList =new CopyOnWriteArrayList<>();
for (int i = 0; i < 1000; i++) {
new Thread(()->{
arrayList.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(arrayList.size());
}
}
死锁
某一个同步块同时拥有"两个以上对象的锁"时,就可能会发生"死锁"的问题
package syn;
/**
* 产生死锁的必要条件
* 1.互斥条件:一个资源每次只能被一个进程使用
* 2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
* 3.不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺
* 4.循环等待条件:若干进程之间形成一种头尾详解的循环等待资源挂关系
*
*/
//死锁:多个线程互相抱着对放需要的资源
public class DeadLock {
public static void main(String[] args) {
Makeup makeup1 = new Makeup(0,"灰姑娘");
Makeup makeup2 = new Makeup(1,"白学公主");
makeup1.start();
makeup2.start();
}
}
//口红
class Lipstick {
}
//镜子
class Mirror {
}
class Makeup extends Thread {
static Lipstick lipstick = new Lipstick();
static Lipstick mirror = new Lipstick();
int choice; //选择
String girlName; //使用化妆品的认
public Makeup(int choice, String girlName) {
this.choice = choice;
this.girlName = girlName;
}
@Override
public void run() {
try {
makeup();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//化妆
private void makeup() throws InterruptedException {
if (choice == 0) {
synchronized (lipstick) {
System.out.println(this.getName() + "获得口红的锁");
Thread.sleep(1000);
}
synchronized (mirror) {
System.out.println(this.getName() + "获得镜子的锁");
}
}else {
synchronized (mirror) {
System.out.println(this.getName() + "获得镜子的锁");
Thread.sleep(2000);
}
synchronized (lipstick) {
System.out.println(this.getName() + "获得口红的锁");
}
}
}
}
Lock
package syn;
import java.util.concurrent.locks.ReentrantLock;
/**
* lock和synchronized的区别
* 1.lock是一个接口,而synchronized 是java中的关键字
* 2.lock可以选择性的获取锁,如果一段时间获取不到,可以放弃。synchronized会一直获取下去。借助lock这个特性,就能规避死锁
* 3.synchronized在发生异常和同步块结束的时候,会自动释放锁。而Lock必须手动释放
*/
//优先使用顺序
Lock ->同步代码块->同步方法啊
public class TestLock {
public static void main(String[] args) {
TestLock2 lock2 = new TestLock2();
new Thread(lock2).start();
new Thread(lock2).start();
new Thread(lock2).start();
}
}
class TestLock2 implements Runnable {
private int ticketNums = 10;
//定义Lock锁
private final ReentrantLock reentrantLock = new ReentrantLock();
@Override
public void run() {
while (true) {
reentrantLock.lock();//加锁
try {
if (ticketNums > 0) {
Thread.sleep(1000);
System.out.println(ticketNums--);
} else {
break;
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
//解锁
reentrantLock.unlock();
}
}
}
}
线程协作-生产者消费者
生产者消费者模式
管程法
package syn;
//测试生产者消费者模型,利用缓冲区解决 :管程法
//生产者,消费者,产品,缓冲区
public class TestPC {
public static void main(String[] args) {
SynContainer synContainer = new SynContainer();
new Productor(synContainer).start();
new Consumer(synContainer,"1号吃货").start();
new Consumer(synContainer,"2号吃货").start();
//todo 模拟多个消费者
}
}
//生产者
class Productor extends Thread {
SynContainer container;
public Productor(SynContainer container) {
this.container = container;
}
@Override
public void run() {
for (int i = 1; i <=100; i++) {
// try {
// Thread.sleep(50);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
container.push(new Chicken(i));
System.out.println("生产了" + i + "只鸡");
}
}
}
//消费者
class Consumer extends Thread {
SynContainer container;
String name;
public Consumer(SynContainer container,String name) {
super(name);
this.container = container;
}
@Override
public void run() {
for (int i = 1; i <=100; i++) {
//
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
container.pop();
System.out.println(Thread.currentThread().getName()+"消费了" + i + "只鸡");
}
}
}
//产品
class Chicken {
//产品编号
int i;
public Chicken(int i) {
this.i = i;
}
}
//缓冲区
class SynContainer {
//需要一个容器大小
Chicken[] chickens = new Chicken[10];
int count = 0;
//生产者放入产品
public synchronized void push(Chicken chicken) {
//如果容器满了,就需要等待消费
if (count == chickens.length) {
//通知消费者消费.生产者等待
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//如果没有满,就绪要丢入产品
chickens[count] = chicken;
count++;
//通知消费者可以消费了
// todo this
this.notifyAll();
}
//消费者消费产品
public synchronized Chicken pop() {
//判断能否消费
//todo 这里采用while比较好
while (count == 0) {
//等待生产者生产,消费者等待
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//如果可以消费
count--;
Chicken chicken = chickens[count];
//吃完了,通知生产者生产
this.notifyAll();
return chicken;
}
}
信号灯法
package syn;
//测试生产者消费者问题2 :信号灯法,标志位解决
public class TestPC2 {
public static void main(String[] args) {
TV pc2 = new TV();
new Player(pc2).start();
new Watcher(pc2).start();
}
}
//生产者 ->演员
class Player extends Thread {
TV tv;
public Player(TV tv){
this.tv=tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if(i%2==0){
this.tv.play("快乐大本营播放中");
}else {
this.tv.play("抖音:记录美好生活");
}
}
}
}
//消费者 ->观众
class Watcher extends Thread{
TV tv;
public Watcher(TV tv){
this.tv=tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
this.tv.watch();
}
}
}
//产品 ->节目
class TV {
//演员表演,观众等待
//观众观看,演员等待
String voice;
boolean flag = true;
//表演
public synchronized void play(String voice) {
while (!flag) {
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("演员表演了 " + voice);
//通知观众观看
this.notifyAll();//通知唤醒
this.voice = voice;
this.flag = !this.flag;
}
//观看
public synchronized void watch() {
while (flag) {
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("观众观看了:" + voice);
//通知演员表演
this.notifyAll();//通知唤醒
this.flag = !this.flag;
}
}
线程通信
方法名 | 作用 |
---|---|
wait() | 表示线程一直等待,直到其他线程通知,与sleep不同,会释放锁 |
wait(long timeout) | 指定等待的毫秒数 |
notify() | 唤醒一个处于等待状态的线程 |
notifyAll() | 唤醒同一个对象上所有wait()方法的线程,优先级高的线程优先调度 |
线程池
好处
1.提高响应速度
2.降低资源消耗
3.便于线程管理
3.1 corePoolSize :核心池的大小
3.2 maximumPoolSize: 最大线程数
3.3 keepAliveTime :线程没有任务时最多保持多长时间后会终止
package syn;
import java.util.concurrent.*;
public class TestPool {
public static void main(String[] args) {
//这个方法不推荐
// ExecutorService service = Executors.newFixedThreadPool(10);
/**
* corePoolSize:核心池大小
* maxmumPoolSzie:最大线程数
*/
ThreadPoolExecutor service = new ThreadPoolExecutor(10,10,
0L,TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
//关闭连接
service.shutdown();
}
}
class MyThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + i);
}
}
}
总结
package syn;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
//回顾线程池的创建
public class ThreadNew {
public static void main(String[] args) {
new Thread01().start();
new Thread(new Thread02()).start();
FutureTask<Integer> task = new FutureTask<Integer>(new Thread03());
new Thread(task).start();
try {
Integer integer = task.get();
System.out.println(integer);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
}
}
//1.继承Thread类
class Thread01 extends Thread {
@Override
public void run() {
System.out.println("继承Thread类");
}
}
//2.实现Runable接口
class Thread02 implements Runnable {
@Override
public void run() {
System.out.println("实现Runnable接口");
}
}
//3.实现Callable接口
class Thread03 implements Callable {
@Override
public Integer call() throws Exception {
System.out.println("继承Callable类");
return 100;
}
}