java学习笔记(九)----多线程
class ThreadDemo1
{ public static void main(String[] args)
{ new TestThread().start(); //用start()默认去调用run()方法
while(true)
{ System.out.println("main():"+Thread.currentThread().getName()); }
}
}
class TestThread extends Thread
{ public void run()
{ while(true)
{ System.out.println("run():"+Thread.currentThread().getName()); }
}
}
1.要将一段代码在一个新的线程上运行,该代码应该在一个类的run函数中,并且run函数所在的类是Thread的子类。 倒过来看,我们要实现多线程,必须编写一个继承了Thread类的子类,子类要覆盖Thread类中的run函数,在子类的run函数中调用想在新线程上运行的程序代码。
2.启动一个新的线程,我们不是直接调用Thread子类对象的run方法,而是调用Thread子类对象的start(从Thread类的继承到的)方法,Thread类对象的start方法将产生一个新的线程,并在该线程上运行该Thread类对象中的run方法。
3.由于线程的代码段在run方法中,那么该方法执行完成以后线程也就相应的结束了,因而我们可以通过控制run方法中循环的条件来控制线程的结束.
----------------------------------------------------------------------------------
***后台线程***
class ThreadDemo1
{ public static vioid main(String[] args)
{ Thread tt=new TestThread();
tt.setDaemon(true); //在start()前加了setDaemon(true)方法,run()中的线程就变成了后台线程
tt.start();
while(true)
{ System.out.println("main():"+Thread.currentThread().getName()); }
}
}
class TestThread extends Thread
{ public void run()
{ while(true)
{ System.out.println("run():"+Thread.currentThread().getName()); }
}
}
说明了,java中只有后台线程,没有前台线程,java程序就会结束。
1.如果我们对某个线程对象在启动(调用start方法)之前调用了setDaemon(ture)方法,这个线程就变成了后台线程。
2.对java程序来说,只要有一个前台线程在运行,这个进程就不会结束,如果一个进程中只有后台线程运行,这个进程就会结束。
-----------------------------------------------------------------------------
***主线程和子线程的合并***
class ThreadDemo1
{ public static vioid main(String[] args)
{ Thread tt=new TestThread();
tt.setDaemon(true);
tt.start();
int index=0;
while(true)
{ if(index++==100)
try{tt.join();} catch(Exception e){} //此处会有异常,所以必须用try,catch
//当主线程运行100遍以后,就把tt对象的线程加入主线程,又成为单线程了,只有tt对象的线程执行完以后,才会继续执行main中的主线程。
// try{tt.join(10000);} catch(Exception e){} 当主线程和子线程合并100000毫秒后,在分开运行
System.out.println("main():"+Thread.currentThread().getName());
}
}
}
class TestThread extends Thread
{ public void run()
{ while(true)
{ System.out.println("run():"+Thread.currentThread().getName()); }
}
}
---------------------------------------------------------------------------------------------------------
***创建线程另一种方法,用Runnable接口***
class ThreadDemo1
{ public static vioid main(String[] args)
{ Thread tt=new Thread(new TestThread()); //创建一个thread的对象, 当线程对象启动时,它就不调用thread类中自带的run()方法,而记为调用Runnalbe中的run()方法
tt.start();
int index=0;
while(true)
{ if(index++==100)
try{tt.join();} catch(Exception e){}
System.out.println("main():"+Thread.currentThread().getName());
}
}
}
class TestThread implements Runnable //它继承Runnable接口,Runnable接口就有一个run()方法
{ public void run()
{ while(true)
{ System.out.println("run():"+Thread.currentThread().getName()); }
}
}
----------------------------------------------------------------------------------------
***用多个线程,去执行一段代码***
帖路售票,四个窗口同时卖100张票,需要四个线程一同去执行一段代码。
class ThreadDemo1
{ public static void main(String[] args)
{ new TestThread().start();
new TestThread().start();
new TestThread().start();
new TestThread().start();
/*这样就是4个线程,但每个线程都是执行各自的代码,它们是在卖各自的100张票,并不是同时执行一段代码。
应改为
TestThread tt=new TestThread();
tt.start();
tt.start();
tt.start();
tt.start();这样还是不行,因为这样就算写再多tt.start()它还是一个线程,
将main中代码改为
TestThread tt=new TestThread();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
只有让TestThread类继承Runnable类,这样写才是四个线程一起去执行同一段代码*/
}
}
class TestThread extends Thread 改为 class TestThread implements Runnable
{ int tickets=100;
public void run()
{ while(true)
{ if(tickets>0)
{ try{Thread.sleep(10);} catch(Exception e){} //Thread.sleep(10)让该线程停10毫秒,其它线程继续执行
System.out.println(Thread.currentThread().getName()+"is saling ticket"+tickets--);
}
}
}
}
***使用Runnable接口创建多线程***
1.适合多个相同程序代码的线程去处理同一资源的情况,把虚拟CPU(线程)同程序的代码、数据有效分离,较好地体现了面向对象的设思想
2.可以避免由于java的单继承特性带来的局限。我们经常碰到这样一种情况,即当我们要将已经继承了某一个类的子类放入多线程中,由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,那么,这个类就只能采用实现Runnable
接口。
3.当线程被构造时,需要的代码和数据通过一个对象作为构造函数实参传递进去,这个对象就是一个实现了Runnable接口的类的实例 (这句看不太懂)
4.事实上,几乎所有多线程应用都可用Runnable接口方式。
----------------------------------------------------------------------------
----------------------------------------------------------------------------
***************多线程的同步*******************
class ThreadDemo1
{
TestThread tt=new TestThread();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
}
}
class TestThread implements Runnable
{ int tickets=100;
public void run()
{ while(true)
{ if(tickets>0)
{ try{Thread.sleep(10);} catch(Exception e){} //Thread.sleep(10)让该线程停10毫秒,其它线程继续执行
System.out.println(Thread.currentThread().getName()+"is saling ticket"+tickets--);
}
}
}
}
//上面的程序在执行时,就会打印出负数来
把TestThread 类改为
class TestThread implements Runnable
{ int tickets=100;
String str=new String(""); //为synchronized定义的对象, 这个对象的定义必须放在run()方法的外面,不能放在里面,如果放里面的话,每个线程调用时,都产生一个新的str对象,这样,每个线程的str对象每回的标志都是1开始,它就失去了synchronized的功能,运行后还会出现负数。
public void run()
{ while(true)
{ synchronized(str) //将代码放入synchronized语句内,形成了同步代码块,在同一时刻只能有一个线程可以进入同步代码块内运行,当该线程离开同步代码块后,其他线程才能进入同步代码块。 synchronized(object){代码块}这里的object可以是任意一个对象。
{ if(tickets>0)
{ try{Thread.sleep(10);} catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"is saling ticket"+tickets--);
}
}
}
}
}
//还可以把上面的TestThread改为
class TestThread implements Runnable
{ int tickets=100;
public void run()
{ while(true)
{ sale(); }
}
public synchronized void sale() //这样调用也可以,在sale()方法前加上synchronized,这样运行后就不会有负数, 这个方法是用this作为同步监视器的。
{ if(tickets>0)
{ try(Thread.sleep(10);) catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"is saling ticket"+tickets--);
}
}
}
-------------------------------------------------------------------
***代码块与函数间的同步***
class ThreadDemo1
{
TestThread tt=new TestThread();
new Thread(tt).start();
try{Thread.sleep(1);} catch(Exception e) {} //让cpu延迟一毫秒,第一个线程就会去运行run()方法中的内容
tt.str=new String("method");
new Thread(tt).start();
}
}
class TestThread implements Runnable
{ int tickets=100;
String str=new String("");
public void run()
{ if(str.equals("method")
{
while(true)
{ sale();
}
}
else
{ while(true)
{ synchronized(this) //此处注意,不能用str,这样就和sale方法用的是同一个对象了,这样就能实现同步了
{ if(tickets>0)
{
System.out.println(Thread.currentThread().getName()+"is saling ticket"+tickets--);
}
}
}
}
public synchronized void sale()
{ if(tickets>0)
{ try(Thread.sleep(10);) catch(Exception e){}
System.out.print("sale():")
System.out.println(Thread.currentThread().getName()+"is saling ticket"+tickets--);
}
}
}
注意:1. 如果没能 try{Thread.sleep(1);} catch(Exception e) {}语句,最后就是所有线程都去调用sale方法,但加了这条语句,不管停多久,cpu就会马上去运行run()方法中的内容。
2. synchronized(this) 这里必须用this,代码块与函数间才能用相同的对象作为同步监视器。
----------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------
***线程间的通信***
class Producer implements Runnable
{ Q q;
public Producer(Q q)
{ this.q=q; }
public void run()
{ int i=0;
while(true)
{ /* synchronized(q)
{ if(q.bFull)
try{q.wait();} catch(Exeption e){}
if(i==0)
{ q.name="zhangsan"
try{Thread.sleep(1);} catch(Exception e){}
q.sex="male";
}
else
{ q.name="lisi";
q.sex="female";
}
q.bFull=true;
q.notify();
} */
// 在Q类中加了put和get方法后,上面注释的代码可改为
---------------------------------------------------
if (i==0)
q.put("zhangsan","male")
else
q.put("lisi","female");
---------------------------------------------------
i=(i+1)%2;
}
}
}
class Consumer implements Runnable
{ Q q;
public Consumer(Q q)
{ this.q=q; }
public void run()
{ while(true)
{ /* synchronized(q)
{ if(!q.bFull)
try{ q.wait();} catch(Exception e){}
System.out.print(q.name);
System.out.println(":"+q.sex);
q.bFull=false;
q.notify();
} */
// 在Q类中加了put和get方法后,上面注释的代码可改为
--------------------------------------------------
q.get();
--------------------------------------------------
}
}
}
class Q
{ String name="unknown"; // private String name="unknown";
String sex="unknown"; // private String sex="unknown";
boolean bFull=false; // private boolean bFull=false;
-------------------------------------------------------------
** public synchronized void put(String name,String sex)
{ if (bFll)
try{ wait(); } catch(Exception e){}
this.name=name;
try{Thread.sleep(1);} catch(Exception e) {}
this.sex=sex;
bFull=true;
notify();
}
** public synchronized void get()
{ if (!bFull)
try{ wait(); } catch(Exception e){}
System.out.print(name);
System.out.println(":"+sex);
bFull=false;
notify();
}
-------------------------------------------------------------
}
class ThreadCommunation
{ public static void main(String[] args)
{ Q q=new Q();
new Thread(new Producer(q)).start();
new Thread(new Consumer(q)).start();
}
}
--Object对象包括三个方法
wait: 告诉当前线程放弃临视器并进入睡眠状态直到其它线程进入同一监视器并调用notify为止。
notify:唤醒同一对象监视器中调用wait的第一个线程。用于类似饭馆有一个空位后通知所有等候就餐的顾客中的第一个可以入座的情况
notifyAll: 唤醒同一对象监视器中调用wait的所有线程,具有最高优先级的线程首先被唤醒并执行。用于类拟某个不定期的培训班终于招生满额后,通知所有学员都来上课的情况。
-----------
| thread t|
-----------
|
-----------------
|synchronized(o)| 线程t得到对象o的lock旗标
-----------------
|
-----------
|o.wait() | 此时线程t被放置在对象o的等待线程池中,t自动释放o的锁旗标
-----------
|
------------
|o.notify()| 当另外的线程执行了对象o的notify()方法后,线程t可能会被从o的等待线程池中释放出来,并且移动到等
------------ 待线程对象o的锁旗标的线程池中,当t得到锁旗标时就会执行下去
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
***线程的生命控制***
class ThreadCommunation
{ public static void main(String[] args)
{ ThreadTest tt=new ThreadTest();
new Thread(tt).start();
for(int i=0; i<100;i++)
{ if (i==50)
tt.stopMe(); // 在第一个线程循环50次后,使第二个线程停下来
System.out.println("main() is running");
}
}
}
class ThreadTest implement Runnable
{ private boolean bStop=false;
public void stopMe()
{ bStop=false; }
public void run()
{ while(bStop)
{ System.out.println(Thread.currentThread().getName()+"is running"); }
}
---------------------------------------------
---------------------------------------------
---------------------------------------------
tt.setDaemon(true); Runnalbe synchronized(this)
try{tt.join(10000);} catch(Exception e){} 当主线程和子线程合并100000毫秒后,在分开运行
try{Thread.sleep(10);} catch(Exception e){} //Thread.sleep(10)让该线程停10毫秒,其它线程继续执行
wait() notify()
java学习笔记(九)----多线程相关推荐
- Java学习笔记5-1——多线程
目录 前言 核心概念 线程创建 继承Thread类 实现Runnable接口 上述两个方法小结 实现Callable接口 并发问题简介 静态代理模式 线程状态 线程停止(stop) 线程休眠(slee ...
- 【Java学习笔记九】多线程
程序:计算机指令的集合,它以文件的形式存储在磁盘上,是应用程序执行的蓝本. 进程:是一个程序在其自身的地址空间中的一次执行活动.进程是资源申请.调度和独立运行的单位,因此,它使用系统中的运行资源.而程 ...
- Java学习笔记2 多线程简单总结
多线程简单总结 1. 相关概念 1.1 线程与进程 进程 线程 1.2 线程调度 分时调度 抢占式调度 1.3 同步与异步 同步 异步 1.4 并发与并行 并发 并行 2. 创建线程 2.1 继承Th ...
- 【Java学习笔记】——多线程
[笔记]跟着狂神学Java-多线程篇 线程/进程 我的理解:电脑上执行的一个游戏窗口是一个进程,每个模式或者按钮是一个线程 继承Thread类 一个类继承了Thread类之后,可以重写Thread类中 ...
- JAVA学习笔记--4.多线程编程 part5.这些年的那些坑
2019独角兽企业重金招聘Python工程师标准>>> 基本要求 没指定线程name. 没有限定线程个数. Thread#stop等被废弃的方法不安全,详见TODO. 注意锁作用的对 ...
- JAVA学习笔记--4.多线程编程 part1.背景知识和内存模型
2019独角兽企业重金招聘Python工程师标准>>> 背景知识 CPU Cache 如上简易图所示,在当前主流的CPU中,每个CPU有多个核组成的.每个核拥有自己的寄存器,L1,L ...
- Java学习笔记5-2——多线程
目录 线程同步 三大不安全案例 一.不安全的买票过程 二.不安全的取钱过程 三.线程不安全的集合 synchronized 解决三大不安全案例 一.解决不安全的买票过程 二.解决不安全的取钱过程 三. ...
- java时间规划书_【计算机本科补全计划】Java学习笔记(九) Java日期时间
正文之前 终于好像仿佛看完了菜鸟教程的Java课程,感觉自己收获颇丰!很好,Java看完之后正愁如何开始进阶呢!结果发现菜鸟还准备了Java实例这种好东西!简直就是教程界的良心啊 !!!没事,先写写笔 ...
- JAVA学习笔记(九)- 初始化块与静态代码块
初始化块 /** 初始化块* 初始化变量方式:声明时.构造函数.代码块* 使用static关键字修饰的代码块,称为静态代码块* * 执行顺序:静态代码块>代码块>构造方法* * 静态代码块 ...
最新文章
- html 高德地图坐标,百度地图,高德地图,HTML5经纬度比较
- input框选中时如何不出灰框_如何建立学习目标:这个SMART原则,你要了解,家长看懂教给孩子...
- 监控haproxy的脚本
- * Linux相关命令
- 玩转动态编译 - 高级篇:一,IL访问静态属性和字段
- Servlet Cookie处理
- python代码翻译-Python编程学习 -- 用十几行代码实现一个翻译器
- 惠普打印机怎么无线连接电脑_惠普打印机连不上无线?怎么解!
- 点击编辑框全选内容java_Android 中使用EditText 点击全选再次点击取消全选功能
- 《Android开发精要》读书笔记——Android应用模型
- CYYMysql 源码解读 3
- 引言(NParsing框架功能简介、NParsing的由来)
- 元宇宙火了!终于有人把虚拟现实(AR/VR/MR)讲明白了
- 增强版在线LEFSe分析和可视化鉴定标志性基因或物种
- java实战--GC终极总结
- 一周搜索热点20170528
- 小葵花妈妈课堂开课了:《Runnable、Callable、Future、RunnableFuture、FutureTask 源码分析》...
- 利用sublime的package Control安装插件
- Qt5.9生成一个Adroid的apk应用实例
- Java计算两个时间的月份差值