文章目录
线程实现
多线程定义
多进程是指操作系统能同时运行多个任务(程序)。
多线程是指在同一程序中有多个顺序流在执行。
- 同时做多件事情。
说起进程,就不得不说程序。 - 程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。而进程则是执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单
位 - 通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程是CPU调度和执行的的单位。
- 注意:很多多线程是模拟出来的,真正的多线程是指有多个cu,即多核,如服务
器。如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错局。
◆线程就是独立的执行路径:
◆在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,9c线程;
◆main(0称之为主线程,为系统的入口,用于执行整个程序;
◆在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与
操作系统紧密相关的,先后顺序是不能认为的干预的。
◆对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制:
◆线程会带来额外的开销,如cpu调度时间,并发控制开销。
◆每个线程在自己的工作内存交互,内存控制不当会造成数据不一致
thread方法
创建线程方式1.继承thread类,2.重写run()方法,3.调节start开启线程
线程开启不一定立即执行,由cpu调度安排。
伪代码
// 定义线程类
public class MyThread extends Thread{
public void run(){
}
}
// 创建线程对象
MyThread t = new MyThread();
// 启动线程。
t.start();
package javaMultithreading;
//创建线程方式1,继承thread类,重写run()方法,调节start开启线程
public class thread1 extends Thread{//继承线程
public void run() {
for (int i = 0; i < 14; i++) {
System.out.println("i");
}
}
public static void main(String[] args) {//线程开启不一定立即执行,由cpu调度执行。先后交替运行
//mian线程,主程序
for (int i = 0; i < 1400; i++) {
System.out.println("………………………………………………………………………………………………");
//开启线程
//创建对象
thread1 th=new thread1();
//调用start方法,start是多线程,如果直接是th.run();,那不会多线程运行。
th.start();
}
}
}
练习下载图片
package javaMultithreading;
//想下载图片
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
//2.把方法变成一个线程类,实现多线程下载
public class 练习thread实现多线程同步下载图片2 extends Thread {
//丢入一个线程类
public String url;
public String name;
public 练习thread实现多线程同步下载图片2(String url, String name) {
this.url = url;
this.name = name;
}
//下载图片方法的执行体,重写run方法
public void run()
{
webdownloader webdownloader=new webdownloader();//创建
webdownloader.dounloader(url,name);//存入参数
System.out.println("下载的文件名为"+name);
}
//通过构造器启动4个线程
public static void main(String[] args) {
练习thread实现多线程同步下载图片2 test1=new 练习thread实现多线程同步下载图片2("https://i1.hdslb.com/bfs/archive/5cf17a05efcbc75d8916c9ed49f0fcfa94af3826.jpg","2.jpg");
练习thread实现多线程同步下载图片2 test2=new 练习thread实现多线程同步下载图片2("https://i1.hdslb.com/bfs/archive/5cf17a05efcbc75d8916c9ed49f0fcfa94af3826.jpg","3.jpg");
练习thread实现多线程同步下载图片2 test3=new 练习thread实现多线程同步下载图片2("https://i1.hdslb.com/bfs/archive/5cf17a05efcbc75d8916c9ed49f0fcfa94af3826.jpg","4.jpg");
练习thread实现多线程同步下载图片2 test4=new 练习thread实现多线程同步下载图片2("https://i1.hdslb.com/bfs/archive/5cf17a05efcbc75d8916c9ed49f0fcfa94af3826.jpg","5.jpg");
//先t1,
test1.start();
test2.start();
test3.start();
test4.start();
}//i1.hdslb.com/bfs/archive/5cf17a05efcbc75d8916c9ed49f0fcfa94af3826.jpg@672w_378h_1c.webp
//构造器
}
//1,写了一个下载器
class webdownloader{
//下载方法
public void dounloader(String url,String name)
{
try { //调用下载包,下载图片
FileUtils.copyURLToFile(new URL(url),new File(name));//
}catch (IOException e)
{
e.printStackTrace();
System.out.println("io异常,dounloader出现问题");
}
}
}
运行顺序不同,同时下载。
Runnable(thread代理)
- 定义MyRunnable类实现Runnable:接口
- 实现run(0方法,编写线程执行体
- 创建线程对象,调用start()方法启动线程
package javaMultithreading;
public class 实现runable的接口3 implements Runnable{
public void run() {
for (int i = 0; i < 144; i++) {
System.out.println("i");
}
}
public static void main(String[] args) {//线程开启不一定立即执行,由cpu调度执行。先后交替运行
实现runable的接口3 one=new 实现runable的接口3();
//创建一个线程对象,通过线程对象来开启我们的线程,代理
Thread thread=new Thread(one);
thread.start();
//简便方法
// new Thread(one).start();
for (int i=0;i<100;i++)
{
System.out.println("我在学习多线程"+i);
}
}
}
总结
thread 与runnable
原理:
thread实现了runnable接口,
继承thread类
-
子类继承thread类具备多线程能力。
-
启动线程:子类对象.start();
-
不建议使用:避免了oop单继承局限性。
实现runnable接口 -
实现接口runnable具有多线程能力。
-
启动线程:传入目标对象+thread对象.start();
-
建议使用:避免单继承局限性,方便灵活,方便同一个对象被多个线程使用。
初识并发
多个线程同时做一件事,造成数据混乱。
package javaMultithreading;
public class 初识b并发 implements Runnable{
private int ticketNums=10;
public void run()
{
while (true)
{
if(ticketNums<=0)
{
break;
}
try {
Thread.sleep(200);
}catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNums--+"票");
}
}
public static void main(String[] args) {
初识b并发 th=new 初识b并发();
new Thread(th,"小明").start();
new Thread(th,"奥迪").start();
new Thread(th,"黄了").start();
}
}
练习案例(龟兔赛跑)
利用兔子会睡觉的时间类来
if(Thread.currentThread().getName().equals("兔子")&&i%10==0)
{
try {
Thread.sleep(2);
}catch (InterruptedException e)
{
e.printStackTrace();
}
package javaMultithreading;
//模拟龟兔赛跑
public class 龟兔赛跑 implements Runnable{
//胜利者
private static String winner;
@Override
public void run() {
for(int i=0;i<=100;i++)//判断比赛是否结束
{ if(Thread.currentThread().getName().equals("兔子")&&i%10==0)
{
try {
Thread.sleep(2);
}catch (InterruptedException e)
{
e.printStackTrace();
}
}
boolean flag=gameover(i);
if(flag)
{
break;
}
System.out.println(Thread.currentThread().getName()+"run in"+i+"步");
}
}
//判断是否完成比赛
public boolean gameover(int steps)
{//判断是否有胜利者
if(winner!=null)
{
return true;
}{
if(steps==100)
{
winner=Thread.currentThread().getName();
System.out.println("winner is"+winner);
return true;
}
}
return false;
}
public static void main(String[] args) {
龟兔赛跑 race=new 龟兔赛跑();
new Thread(race,"兔子").start();
new Thread(race,"龟龟").start();
}
}
实现callable
-
实现接口,需要返回值类型
-
重写call方法,需要抛出异常
-
创建目标对象
-
创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
-
提交执行:Future result1 = ser.submit(t1);
-
获取结果:boolean r1 = result.get()
-
关闭服务:ser.shutdownNow()
-
可以定义返回值,可以抛出异常
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
class MyThread implements Callable<String>{
private int ticket=5;
public String call() throws Exception{
for(int x=0;x<100;x++){
if(this.ticket>0){
System.out.println("卖票,ticket="+this.ticket--);
}
}
return "票已卖光!";
}
}
public class Demo{
public static void main(String[] args){
MyThread mt1=new MyThread();
MyThread mt2=new MyThread();
FutureTask<String> task1=new FutureTask<String>(mt1);
FutureTask<String> task2=new FutureTask<String>(mt2);
new Thread(task1).start();
new Thread(task2).start();
try {
System.out.println("A线程返回结果:"+task1.get());
System.out.println("B线程返回结果:"+task2.get());
} catch (InterruptedException | ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
静态代理(对比thread)
真实对象和代理对象都有实现同一个接口
代理对象要代理真实角色。
代理对象可以做真实对象做不了的事,真实对象专注做自己的事情
package javaMultithreading;
public class 静态代理 {
public static void main(String[] args) {//代理
You you=new You();//你要结婚
new Thread(()-> System.out.println("我爱你")).start();//也相当于代理
new marrycompany(new You()).happymarry();
// marrycompany company=new marrycompany(you);//创建一个you的对象传给marrycompany
// company.happymarry();
}
}
interface marry{//接口
void happymarry();
}
//真实
class You implements marry{//继承marry接口,实现实例化对象
public void happymarry()
{
System.out.println("结婚");
}
}
//代理
class marrycompany implements marry{//继承marry接口,实现实例化对象
private marry target;
public marrycompany(marry target) {//代表需要传入marry类型的类
this.target = target;
}
@Override
public void happymarry() { //这个方法调用下面2个方法(函数)
before();
this.target.happymarry();
after();
}
private void after() {
System.out.println("结婚之后");
}
private void before() {
System.out.println("结婚之前");
}
}
lamda表达式
任何一个接口,如果只包含一个抽象方法,那么就是函数类接口。
对于函数式接口,亦可用lamda表达式。
//1 ambda表达式只能有一行代码的情况下才能简化成为一行,如果有多行,那么就用代码块包裹。
/1前提是接口为函数式接口
//多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号,
package javaMultithreading;
//任何一个接口,如果只包含1个
//推导lambda表达式
public class Lamda表达式 {
//静态内部类
static class like2 implements Ilike
{
//实现类
@Override
public void iambda() {
System.out.println(" i am good boy2");
}
}
public static void main(String[] args) {
Ilike like = new like();
like.iambda();//外部类
System.out.println("************************************");
like = new like2();//静态累不累
like.iambda();
System.out.println("************************************");
//局部内部类
class like3 implements Ilike { //实现类
@Override
public void iambda() {
System.out.println(" i am good boy3");
}
}
like = new like3();
like.iambda();
System.out.println("************************************");
//匿名类部类
like = new like() {
public void iambda() {
System.out.println("i am iambda4");
}
};
like.iambda();
//用lamda简化
like = () -> {
System.out.println("i like kambda5");
};
like.iambda();
}
}
// 定义一个函数式接口
interface Ilike{
void iambda();
}
class like implements Ilike
{
//实现类
@Override
public void iambda() {
System.out.println(" i am good boy1");
}
}
线程状态
5大状态
setPriority:更改线程优先级
sleep:在指定的毫秒数内让当前正在执行的线程休眠
join:等待该线程终止
yield:暂停当前正在执行的线程对象,并执行其他线程
interrupt:中断线程
isAlive:测试线程是否处于活动状态
线程停止
建议线程正常停止,利用次数或标志位
不要使用stop,destory等不建议使用的方法。
package javaMultithreading;
//测试stop
//建议线程正常停止--->利用次数,不建议死循环。
//建议使用标志位-一>设置一个标志位
//不要使用stop或者destroy等过时或者JD人
public class 线程停止 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) {
线程停止 stop=new 线程停止();
new Thread(stop).start();
for (int i = 0; i < 1000; i++) {
System.out.println("mian"+i);
if(i==900)
{ //调用stop方法切换标准位,让线程停止
stop.stop();
System.out.println("线程停止");
}
}
}
}
线程休眠 sleep
◆sleep(时间)指定当前线程阻塞的毫秒数;
◆sleep存在异常InterruptedException;
◆sleepl时间达到后线程进入就绪状态;
sleep可以模拟网络延时,倒计时等。
每一个对象都有一个锁,sleep不会释放锁;
package javaMultithreading;
import java.text.SimpleDateFormat;
import java.util.Date;
//模拟网络延迟
public class sleep类 {
public static void main(String[] args) {
//打印当前时间
Date startTime =new Date(System.currentTimeMillis());
while (true)
{
try {
Thread.sleep(1000);
System.out.println(new SimpleDateFormat("hh:mm:ss").format(startTime));
startTime =new Date(System.currentTimeMillis());//获取系统当前时间
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
线程礼让
礼让线程,让当前正在执行的线程暂停,但不阻塞
将线程从运行状态转为就绪状态
让cpu重新调度,礼让不一定成功!看CPU心情
public void run() {
Thread.yield();//礼让
}
package javaMultithreading;
public class 礼让 {
public static void main(String[] args) {
myyield my=new myyield();
new Thread(my,"小明").start();
new Thread(my,"大明").start();
}
}
class myyield implements Runnable
{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程开始执行");
Thread.yield();//礼让
System.out.println(Thread.currentThread().getName()+"线程停止执行");
}
}
强制执行join
(插队)
package javaMultithreading;
public class 强制执行 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("线程vip"+i);
}
}
public static void main(String[] args) {
强制执行 qz=new 强制执行();
Thread thread=new Thread(qz);
thread.start();
//主线程
for (int i = 0; i < 1111; i++) {
if(i==200)
{
try {
thread.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("main"+i);
}
}
}
线程观测状态
package javaMultithreading;
public class 观测线程状态 {
public static void main(String[] args) {
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);//run
while (state!=Thread.State.TERMINATED) //当他没死亡时,输出状态
{
try {
Thread.sleep(100); //调用sleep方法,wait同步锁定时,线程进入阻塞状态,解除之后等待cpu调度。
state=thread.getState();//获取线程状态的时候会更新,不更新就不会变。
System.out.println(state);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
thread.start();//停止之后不能再运行。
}
}
死亡之后无法运行
Exception in thread “main” java.lang.IllegalThreadStateException
at java.lang.Thread.start(Thread.java:710)
线程优先级 PRIORITY
改变或者获取优先级getPriority().setPriority(int xxx)
优先级低只是意味着获得调度的
概率低.并不是优先级低就不会
被调用了.这都是看CPU的调度
主线程优先级默认。
package javaMultithreading;
public class 线程优先级 {
public static void main(String[] args) {
//主线程默认优先级
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
MYPRINTITY myprintity=new MYPRINTITY();
Thread t1=new Thread(myprintity);
Thread t2=new Thread(myprintity);
Thread t3=new Thread(myprintity);
Thread t4=new Thread(myprintity);
Thread t5=new Thread(myprintity);
//设置优先级,先设置优先级再启动
t1.start();//默认优先级5
t2.setPriority(2);
t2.start();
t3.setPriority(4);
t3.start();
t4.setPriority(Thread.MAX_PRIORITY);
t4.start();
t5.setPriority(6);
t5.start();
}
}
class MYPRINTITY implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
}
}
守护线程(daemon)
setDaemon设置为守护线程。
线程分为用户线程和守护线程
虚拟机必须确保用户线程执行完毕
虚拟机不用等待守护线程执行完毕
如,后台记录操作日志,监控内存,垃圾回收等待
package javaMultithreading;
public class 守护线程 {
public static void main(String[] args) {
god g=new god();
you y=new you();
Thread thread=new Thread(g);
thread.setDaemon(true); //守护线程,默认为false
thread.start();//god启动
new Thread(y).start();//你启动
}
}
//上帝
class god implements Runnable
{
@Override
public void run() {
while (true) {
System.out.println("上帝保佑你");
}
}
}
// 守护你
class you implements Runnable
{
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("活着");
}
System.out.println("goodbye!");
}
}
线程同步synchronized
-
为了避免抢票
-
多个线程操作同一个对象。
-
使用队列+锁保证同步
-
损失性能,优先级高的线程等待一个优先级低的线程释放锁,线程倒置。
-
重点:
synchronized后面小括号() 中传的这个“数据”是相当关键的。这个数据必须是 多线程共享 的数据。才能达到多线程排队,不然白白损失效率。
线程同步安全
可以通过private关键字来保证数据对象只能被方法访问,所以只需要针对方法提出一套机制,这就是synchronized关键字,包括两种用法:synchronized方法和synchronized块。
package javaMultithreading.线程同步;
//原因在于线程的内存都是独立的,各自的。
public class 不完全取钱 {
public static void main(String[] args) {
Account account=new Account(100,"结婚鸡精");
Drawing you=new Drawing(account,50,"ffffff");
Drawing girl=new Drawing(account,80,"girl");
you.start();
girl.start();
}
}
class Account{
int monry;//余额
String name;//卡号
public Account(int monry, String name) {
this.monry = monry;
this.name = name;
}
}
//银行
class Drawing extends Thread{
Account account;//账户
//取多少钱
int drawingmoney;
//现在有多少
int nowmoney;
public Drawing( Account account,int drawingmoney,String name)
{ super(name);
this.account=account;
this.drawingmoney=drawingmoney;
}
//取钱
public void run()
{
if(account.monry-drawingmoney<0)
{
System.out.println(Thread.currentThread().getName()+"钱不够");
return;
}
//sleep放大问题发生性
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//卡内余额=余额-你取的钱
account.monry-=drawingmoney;
//你手里的钱
nowmoney=nowmoney+drawingmoney;
System.out.println(account.name+"余额为:"+account.monry);
//Thread.currentThread().getName()=this.getName();
System.out.println(this.getName()+"手里的钱"+nowmoney);
System.out.println("卡里的钱"+account.monry);
}
}
线程
同步方法
可以通过private关键字来保证数据对象只能被方法访问,所以只需要针对方法提出一套机制,这就是synchronized关键字,包括两种用法:synchronized方法和synchronized块。
synchronized方法
同步方法
public synchronized void method(int args){}
synchronized方法控制对“对象”的访问,每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞。方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行。
缺陷:若将一个大的方法申明为synchronized将会影响效率。
synchronized块
sychronized (Obj){}
Obj称之为同步监视器
obj可以是任何对象,但推荐使用共享资源作为同步监视器,锁的对象就是变化的量
同步方法中无需指定同步监视器,因为同步方法的同步监视器是this,就是对象本身,或者是class
同步监视器执行过程
第一个线程访问,锁定同步监视器,执行其中代码
第二个线程访问,发现同步监视器被锁定,无法访问
第一个线程访问完毕,解锁同步监视器
第二个线程访问,发现同步监视器没锁,然后锁定并访问
死锁
多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行。某一个同步块同时拥有“两个以上对象的锁”时,就可能发生“死锁"现象。
产生死锁的四个必要条件:
互斥条件:一个资源每次只能被一个进程调用
请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺
循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。。
package javaMultithreading.线程同步;
public class 死锁 {
public static void main(String[] args) {
makup g1=new makup(0,"灰姑凉");
makup g2=new makup(1,"baixgzhu1");
g1.start();
g2.start();
}
}
class Lipaatick{
}
//镜子
class Mirror{
}
class makup extends Thread{
static Lipaatick lipaatick =new Lipaatick();
static Mirror mirror=new Mirror();
int choice;//选择
String girlName;//使用化妆品的人
makup(int choice,String girlName)
{
this.choice=choice;
this.girlName=girlName;
}
public void run()
{//化妆
makeup();
}//化妆,需要对方资源
private void makeup()
{
if(choice==0)
{
synchronized (lipaatick){//
System.out.println(this.getName()+"获得口红是锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}synchronized (mirror)
{
System.out.println(this.girlName+"获得镜子的锁");
}
}else {
synchronized (mirror){//获得口红的锁
System.out.println(this.getName()+"获得镜子是锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} synchronized (lipaatick)
{
System.out.println(this.girlName+"获得口红的锁");
}
}
}
}
Lock(锁)
可重入锁。
synchronized与Lock的对比
◆Lock是显式锁(手动开启和关闭锁,别忘记关闭锁)synchronized是隐式锁,出了
作用域自动释放
◆Lock只有代码块锁,synchronized有代码块锁和方法锁
◆使用Lock锁,JM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展
性(提供更多的子类)
◆优先使用顺序:
◆LOCk>同步代码块(已经进入了方法体,分配了相应资源)>同步方法(在方
法体之外)
ReentrantLock lock = new ReentrantLock();
try{
lock.lock();
....
}finally{
lock.unlock();
}```
```java
package javaMultithreading.线程同步;
import java.util.concurrent.locks.ReentrantLock;
//lock锁
public class 锁 {
public static void main(String[] args) {
teatlock teatlock=new teatlock();
new Thread(teatlock).start();
new Thread(teatlock).start();
new Thread(teatlock).start();
new Thread(teatlock).start();
}
}
class teatlock implements Runnable{
int ticketnumber=10; //定义lock锁
private final ReentrantLock lock=new ReentrantLock();
public void run() {
while (true)
{
try {
lock.lock();
if(ticketnumber>0)
{
try {
Thread.sleep(1000);
}catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println(ticketnumber--);
}else {
break;
}
}finally {
//解锁
lock.unlock();
}
}
}
}
线程协作
应用场景:生产者和消费者问题
◆
假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将
仓库中产品取走消费
◆如果仓库中没有产品,则生产者将产品放入仓库,否则停止生产并等待,直到
仓库中的产品被消费者取走为止
◆如果仓库中放有产品,则消费者可以将产品取走消费,否则停止消费并等待,
直到仓库中再次放入产品为止
生产者 —》缓冲区—》消费者
方法
wait():表示线程会一直等待,直到其他线程通知,与sleep不同,会释放锁
wait(long timeout):指定等待的毫秒数
notify():唤醒一个处于等待状态的线程
notifyAll():唤醒同一个对象上所有调用wait()方法的进程,优先级别高的线程优先调度。
都是object类的方法,都只能在同步方法或者同步代码块中使用,否则会抛出异常IllegalMonitorStateException
### 管程法
package javaMultithreading.线程协作;
//测试生产者消费者模型-管程法
//生产者,消费者,产品,缓冲区
public class 管理法 {
public static void main(String[] args) {
//容器
syncontainer container=new syncontainer();
//对象
new protuct(container).start();
new Consumer(container).start();
}
}
//生产者
class protuct extends Thread
{
syncontainer container;
public protuct(syncontainer container)
{
this.container=container;
}
//run 生产
public void run()
{
for (int i = 0; i < 100; i++) {
container.push(new chicken(i));
System.out.println("生产了第"+i+"只鸡");
}
}
}
//消费者
class Consumer extends Thread
{
syncontainer container;
public Consumer(syncontainer container)
{
this.container=container;
}
//消费
public void run()
{
for (int i = 0; i < 100; i++) {
System.out.println("消费了第"+container.pop().id+"只鸡");
container.push(new chicken(i));
}
}
}
//产品
class chicken {
int id;
//产品编号
public chicken (int id)
{
this.id=id;
}
}
//缓冲区
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++;
//通知消费者消费
this.notify();
}
public synchronized chicken pop(){
//判断能否消费
if(count==0)
{//等待生产者生产
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//如果可以消费
count--;
chicken chicken=chickens[count];
//吃完了,通知生产者生产
this.notifyAll();
return chicken;
}
}
信号灯法
通过标志位
package javaMultithreading.线程协作;
public class 信号灯法 {
public static void main(String[] args) {
tv t=new tv();
new player(t).start();
new player(t).start();
}
}
//生产者-演员
class player extends Thread{
tv t;
public player(tv t)
{
this.t=t;
}
public void run()
{
for (int i = 0; i < 20; i++) {
if(i%2==0)
{
try {
this.t.play("ff");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}else {
try {
this.t.play("ffdfdfds");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
//消费者-观众
class watcher extends Thread{
tv t;
public watcher(tv t)
{
this.t=t;
}
}
//节目
class tv {
//表演//演员表演,观众等待T
///1观众观看,演员等待f
String voice;
boolean flag=true;
//表演
public synchronized void play (String voice) throws InterruptedException {if(flag!=true) {
this.wait();
}
System.out.println("演员表演了:"+voice);
//通知观众观看
this.notifyAll();//通知唤醒
this.voice=voice;
this.flag=!this.flag;
}
//观众看
public synchronized void watch() throws InterruptedException {
if (flag) {
this.wait();
System.out.println("观众观看了" + voice);
//通知演员表演
this.notifyAll();
this.flag=!this.flag;
}
}
}
使用线程池
原因:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影
响很大。
思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。
可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具。
好处:
◆提高响应速度
(减少了创建新线程的时间)
降低资源消耗(重复利用线程池中线程,不需要每次都创建)
◆
便于线程管理(…)
◆corePoolSize:核心池的大小
maximumPoolSize:最大线程数
keepAliveTime:线程没有任务时最多保持多长时间后会终止
package javaMultithreading.线程协作;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class 线程池 {
//产生线程池
public static void main(String[] args) {
//创建服务
//参数为池子大小
ExecutorService service= Executors.newFixedThreadPool(10);
service.execute(new mythread());
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<111;i++)
{
System.out.println(Thread.currentThread().getName());
}
}
}