一、线程概念
1.进程:是一个正在执行中的程序;
每一个进程执行都有一个执行顺序,该顺利是一个执行路径,或者叫一个控制单元
2.线程:就是进程中的一个独立的控制单元。线程控制着进程的执行;
一个进程中可以多执行路径,称之为多线程。
一个进程中至少要有一个线程。
3.为什么要用多线程?
开启多个线程是为了同时运行多部分代码。
每一个线程都有自己运行的内容。这个内容可以称为线程要执行的任务。
4.多线程好处:解决了多部分同时运行的问题。
多线程的弊端:线程太多回到效率的降低。
5.多线程的原理:
其实应用程序的执行都是cpu在做着快速的切换完成的,这个切换是随机的。
JVM启动时就启动了多个线程,至少有两个线程可以分析的出来。
(1)执行main函数的线程,
该线程的任务代码都定义在main函数中。
(2)负责垃圾回收的线程。
二、创建线程
两种方式:继承thread类和实现Runnable接口
1.继承Thread类方法
如何在自定义代码中,自定义一个线程呢?
通过对API的查找,java已经提供给了对线程这类事物的封装和描述。就Thread类。
创建步骤:
(1).定义类继承Thread。
(2).复写Thread类中的run方法;
目的:将自定义代码存储在run方法。让线程运行;
为什么要覆盖run方法呢?
thread类用于描述线程。
该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法。
也就是说,thread类中的run方法,用于存储线程要运行的代码;
(3).调用线程的Start方法;
该方法两个作用:启动线程,调用run方法;
注意:发现运行结果每一次都不同。
因为多个线程都获取cpu的执行权。cpu执行到谁,谁就运行。
明确一点,在某一个时刻,只能有一个程序在运行。(多核除外)
cpu在做着快速的切换,以达到看上去是同时运行的效果。
我么可以形象把多线程的运行行为看做是在抢夺cpu的执行权;
这就是多线程的一个特性:随机性。谁抢到谁执行,至于执行多长时间,cpu说了算
举例:
package day04;
class Test extends Thread
{
private String name;
Test(String name)
{
super(name);
this.name=name;
}
//覆盖thread类run方法
public void run(){
for(int i=0;i<60;i++)
{
System.out.println(Thread.currentThread().getName()+"---run---"+i);
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
Test t1=new Test("one");//创建好一个线程;
Test t2=new Test("two");
t1.start();//开启线程,并执行该线程的run方法;
t2.start();
//t1.run();//仅仅是对象调用方法。而线程创建了,并没有运行。
//t2.run();
for(int i=0;i<60;i++)
{
System.out.println("main run--"+i);
}
}
}
总结:当调用run方法时,并没有启动一个线程,仍然只是一个main线程在运行;
创建线程方式一:
1.子类覆盖父类的run方法,将线程运行的代码存放在run中;
2.建立子类对象的同时,线程也被创建;
3.调用start方法开启现线程;
线程的四种状态:创建,运行,冻结,消亡 (关系如图)
一个特殊的状态:就绪:具备了执行资格,但是还没有获取资源。
2.实现Runnable接口
创建线程的第二种方式:实现Runable接口
步骤:
(1).定义类实现Runable接口
(2).覆盖Runable接口中的run方法;
将线程要运行的代码存放在该run方法中;
(3).通过Thread类建立线程对象;
(4).将Runable接口的子类对象作为实际参数传递给Thread类的构造函数;
为什么要将Runable接口的子类对象传递给Thread的构造函数;
因为自定义的run方法所属的对象是Runnable接口的子类对象。
所以要让线程去指定对象的run方法;
(5).调用Thread类的start方法开启线程并调用Runnable接口子类run方法;
实现方式好处:避免了单继承方式有什么区别呢?
实现方式的好处:避免了单继承的局限性;
在定义线程时,建议使用实现方式;
如图:比喻解释学生是人的子类,但是学生类的部分代码被多线程执行,这时提供接口(java只支持单继承),学生是人中的一种,学生像Runnable,接口的好处提供了额外的功能;
两种方式的区别:
继承Thread:线程代码存放在Thread子类run方法中;
实现Runnable,线程代码存放在接口的子类的run方法;
举例:
package day04;
/*
需求:简单的卖票程序。
多个窗口卖票。
*/
class Ticket implements Runnable
{
private int tick = 100;
public void run()
{
while(true)
{
if(tick>0)
{
//显示线程名及余票数
System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--);
}
}
}
}
public class TicketDemo
{
public static void main(String[] args)
{
//创建Runnable接口子类的对象
Ticket t = new Ticket();
//创建四个线程,把Runable的子类对象作为参数传给Thread类的构造函数
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
Thread t4 = new Thread(t);
//启动线程
t1.start();
t2.start();
t3.start();
t4.start();
}
}
买票程序:
需求:简单的卖票程序。多个窗口同时卖票;
//使用继承
class Ticket extends Thread
{
public int tick = 100;
public void run()
{
while(true)
{
if(tick>0)
System.out.println(Thread.currentThread().getName()+"....sale:"+tick--);
}
}
}
class TickDemo
{
public static void main(String arg[])
{
Ticket t1 = new Ticket();
Ticket t2 = new Ticket();
Ticket t3 = new Ticket();
Ticket t4 = new Ticket();
t1.start();
t2.start();
t3.start();
t4.start();
//如果new四个线程,则会有四百张票,当然我们可以把tick改成静态的,但我们一般不这样做,因为static的声明周期太长;
Ticket t1 = new Ticket();
t1.start();
t1.start();
t1.start();
t1.start();
//如果new一个线程,编译会出错;
}
}
两种方式区别:第一种是卖400张票,第二种100张建立使用实现方式;
三、线程安全问题
1.问题的原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。导致共享数据的错误;
2.解决问题:
对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他不可以参与执行;
java的专门解决方法:
(1)同步代码块.
synchronized(对象)
{
需要被同步的代码;
}
对象如同锁,持有锁的线程可以再同步中执行;
没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有锁;
火车卫生间例子
举例:
package day04;
/*
给卖票程序示例加上同步代码块。
*/
class Ticket implements Runnable
{
private int tick=100;
Object obj = new Object();
public void run()
{
while(true)
{
//给 共享数据tick加同步,即锁
synchronized(obj)
{
if(tick>0)
{
try
{
//使用线程中的sleep方法,暴露线程的不安全问题;
//因为sleep方法有异常,try catch一下
Thread.sleep(10);
}
catch (Exception e)
{
}
System.out.println(Thread.currentThread().getName()+"..tick="+tick--);
}
}
}
}
}
public class TicketDemo
{
public static void main(String arg[])
{
Ticket t = new Ticket();
Thread t1= new Thread(t);
Thread t2= new Thread(t);
Thread t3= new Thread(t);
Thread t4= new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
(2)同步函数
格式:
在函数上加上synchronized修饰符
与同步代码块的区别:如果函数中的全部代码都是共享数据,则用同步函数,如果是部分,则用同步代码块。
验证同步函数的锁是谁?
package day04;
class Ticket implements Runnable {
public static int tick = 100;
// public static int tick = 100;
// Object obj =new Object();
boolean flag = true;
public void run() {
if (flag) {
while (true) {
// synchronized(Ticket.class)
synchronized (this)// 把obj改为this使两把锁相同;
{
if (tick > 0) {
// sleep(10)暴露线程的不安全问题;
try {
Thread.sleep(100);
} catch (Exception e) {
}
System.out.println(Thread.currentThread().getName()
+ "....one:" + tick--);
}
}
}
}
else
while (true)
show();
}
public static synchronized void show()
//public synchronized void show()// this
{
if (tick > 0) {
// sleep(10)暴露线程的不安全问题;
try {
Thread.sleep(10);
} catch (Exception e) {
}
System.out.println(Thread.currentThread().getName() + "...two:"
+ tick--);
}
}
}
public class TicketDemo {
public static void main(String arg[]) {
Ticket t = new Ticket();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t.flag=false;
t2.start();
}
}
结果发现错票,说名同步的两个前提,没有满足,一、两个以上线程 二必须是同一把锁,可看出是锁不相同,所以同步函数的锁不是obj,而是this
举例1:
package day04;
/*
给卖票程序示例加上同步代码块。
*/
class Ticket implements Runnable {
private int tick = 100;
public void run() {
while (true) {
show();
}
}
//对共享数据用同步函数封装
public synchronized void show() {
if (tick > 0) {
try {
// 使用线程中的sleep方法,暴露线程的不安全问题;
// 因为sleep方法有异常,try catch一下
Thread.sleep(10);
} catch (Exception e) {
}
System.out.println(Thread.currentThread().getName() + "..tick="
+ tick--);
}
}
}
public class TicketDemo {
public static void main(String arg[]) {
Ticket t = new Ticket();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
Thread t4 = new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
举例2
package day04;
/*需求:银行有一个金库。有两个储户分别存300元,每次存100,存三次;
目的:改程序时候有安全问题,如果有,如何解决;
如何找问题:
1.明确哪些代码是多线程运行代码。
2.明确共享数据;(一般成员变量都是共享数据,不能分开执行)
3.明确多线程运行代码中哪些语句是操作共享数据的
*/
class Bank {
private int sum;
// Object obj = new Object();
//.明确共享数据;
public synchronized void add(int n)// 同步函数
{
// synchronized(obj)
// {
sum = sum + n;
try {
Thread.sleep(10);
} catch (Exception e) {
}
System.out.println("sum=" + sum);
// }
}
}
class Cus implements Runnable {
private Bank b = new Bank();
//.明确哪些代码是多线程运行代码。
public void run() {
for (int x = 0; x < 3; x++) {
b.add(100);
}
}
}
public class BankDemo {
public static void main(String args[]) {
Cus c = new Cus();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
t1.start();
t2.start();
}
}
同步的前提:
(1).同步(共享数据)代码中必须要有两个或者两个以上的线程。
(2)必须是多个线程使用同一个锁。
必须保证同步中只能有一个线程运行;
好处:解决了多线程的安全问题;
弊端:多个线程需要判断锁,较为消耗资源;
3.如果同步函数被静态修饰后,使用的锁是什么呢:
举例:
package day04;
class Ticket implements Runnable {
public static int tick = 100;
// public static int tick = 100;
// Object obj =new Object();
boolean flag = true;
public void run() {
if (flag) {
while (true) {
// synchronized(Ticket.class)
synchronized (this)// 把obj改为this使两把锁相同;
{
if (tick > 0) {
// sleep(10)暴露线程的不安全问题;
try {
Thread.sleep(100);
} catch (Exception e) {
}
System.out.println(Thread.currentThread().getName()
+ "....one:" + tick--);
}
}
}
}
else
while (true)
show();
}
public static synchronized void show()
//public synchronized void show()// this
{
if (tick > 0) {
// sleep(10)暴露线程的不安全问题;
try {
Thread.sleep(10);
} catch (Exception e) {
}
System.out.println(Thread.currentThread().getName() + "...two:"
+ tick--);
}
}
}
public class TicketDemo {
public static void main(String arg[]) {
Ticket t = new Ticket();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t.flag=false;
t2.start();
}
}
结果发现错票,说明静态同步函数的锁不是this,而是类名. class
静态进内存是,内存中没有本类对象,但是一定有该类对应的字节码文件对象,类名.class 该对象的类型是class
静态的同步方法,使用的锁是该方法所在类的字节码文件对象。类名.class
4.多线程 --单例设计模式;
对于饿汉式不会发生安全问题,因为 他的共享数据只有一句,而懒汉式会发生线程安全问题,
package day04;
class Single {
private static Single s = null;
private Single() {
}
//加同步函数已经解决了同步问题,但是比较低效
public static synchronized Single getInstance() {
if (s == null) {
s = new Single();
}
return s;
}
}
public class SingleDemo {
public static void main(String args[]) {
}
}
改为:判断锁的次数太多,低效,改为双重判断,减少判断锁的次数,提高效率。如下:
package day04;
class Single {
private static Single s = null;
private Single() {
}
public static Single getInstance() {
// 懒汉式加同步函数,比较低效;加双重判断减少判断锁的次数;
if (s == null) {
synchronized (Single.class) {
if (s == null)
s = new Single();
}
}
return s;
}
}
public class SingleDemo {
public static void main(String args[]) {
}
}
5.死锁:
同步中嵌套同步,锁却不同;
举例1:
package day04;
class Ticket1 implements Runnable
{
private int tick=1000;
Object obj= new Object();
boolean flag =true;
public void run()
{
if(flag){
while(true)
{
synchronized (obj) {
//拥有obj锁,有需要this锁
show();
}
}
}
else
while(true)
show();
}
//拥有this锁,需要obj锁
public synchronized void show()
{
synchronized (obj) {
if(tick>0)
{
try {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+"------code----"+tick--);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
public class SiSuoDemo {
public static void main(String[] args) {
Ticket1 t=new Ticket1();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
t1.start();
try {
//让主线程睡眠一段时间,否则主线程跑的太快,不容易出现死锁现象
Thread.sleep(1010);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t.flag=false;
t2.start();
}
}
举例2:
package day04;
class Test1 implements Runnable {
static Object locka = new Object();
static Object lockb = new Object();
private boolean flag = true;
Test1(boolean flag) {
this.flag = flag;
}
public void run() {
if (flag) {
while (true) {
//互相持有对方的锁
synchronized (locka) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("if lock");
synchronized (lockb) {
System.out.println("if lock");
}
}
}
} else {
while (true) {
synchronized (lockb) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("else lock");
synchronized (locka) {
System.out.println("else lock");
}
}
}
}
}
}
public class DeadLockTest {
public static void main(String[] args) {
Thread t1 = new Thread(new Test1(true));
Thread t2 = new Thread(new Test1(false));
t1.start();
t2.start();
}
}
6.线程间通讯:
其实就是多个线程在操作同一个资源,但是操作的动作不同。
举例:
package day04;
/*
有一个资源
一个线程往里存东西,如果里边没有的话
一个线程往里取东西,如果里面有得话
*/
//资源
class Resource
{
private String name;
private String sex;
private boolean flag=false;
public synchronized void set(String name,String sex)
{
if(flag)
{
try{wait();}catch(Exception e){}//如果有资源时,等待资源取出
}
this.name=name;
this.sex=sex;
flag=true;//表示有资源
notify();//唤醒等待
}
public synchronized void out()
{
if(!flag)
{
try{wait();}catch(Exception e){}//如果木有资源,等待存入资源
}
System.out.println("name="+name+"---sex="+sex);//这里用打印表示取出
flag=false;//资源已取出
notify();//唤醒等待
}
}
//存线程
class Input implements Runnable
{
//定义资源对象成员变量;
private Resource r;
// 初始化拥有资源,如果Resourse r = new Resource()不能保证资源对象的唯一性,因为output类中也会这样写,这时是两份资源,
//让Input初始化时就通过构造函数拥有资源对象,而对象只要建立一次,就可以了,当然要把对象的引用传进来,
Input(Resource r)
{
this.r=r;
}
//复写run方法
public void run()
{
int x=0;
while(true)
{
//交替存入Mike和丽丽
if(x==0)
{
r.set("mike",".....man");
}
else
{
r.set("丽丽","..女女女女");
}
x=(x+1)%2;
}
}
}
//取线程
class Output implements Runnable
{
private Resource r;
Output(Resource r)
{
this.r=r;
}
//复写run方法
public void run()
{
while(true)
{
r.out();
}
}
}
public class InputOutputDemo
{
public static void main(String[] args)
{
Resource r = new Resource();//建立一个资源
new Thread(new Input(r)).start();//开启存线程
new Thread(new Output(r)).start();//开启取线程
}
}
注意:
1.wait(),notify(),notifyAll() 这些方法都使用在同步中,因为要对持有监视器(锁)的线程操作,所以要使用在同步中,因为只有同步才具有锁;
2.为什么这些操作线程的方法要定义在object类总呢?
因为这些方法在操作同步中线程时,都必须要标示他们所操作线程只有的锁。
只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒。
不可以对不同锁的线程进行唤醒;
也就是说,等待和唤醒必须是同一个锁。
而锁可以使任意对象,所以可以被任意对象调用的方法定义object类中。
拓展:生产者与消费者
对于多个生产者和消费者。
为什么要定义while判断标记;
原因:让被唤醒的线程再一次判断标记;
为什么定义notifyAll因为要唤醒对方线程;
package day04;
class Resource1 {
private String name;
private int count = 1;
boolean flag=false;
public synchronized void set(String name) {
while(flag)//使用while判断,让被唤醒的线程再一次判断标记
try {
wait();
} catch (InterruptedException e) {
}
this.name =name+"----"+count++;
System.out.println(Thread.currentThread().getName()+"--生产者---"+this.name);
flag=true;
this.notifyAll();//唤醒对方线程
}
public synchronized void out()
{
while(!flag)
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"消费者"+this.name);
flag =false;
this.notifyAll();//唤醒对方线程
}
}
//生产者
class Producer implements Runnable
{
private Resource1 res;
//初始化生产者
Producer(Resource1 res)
{
this.res=res;
}
public void run() {
while(true)
res.set("商品");
}
}
// 消费者
class Consumer implements Runnable
{
private Resource1 res;
//初始化消费者
Consumer(Resource1 res)
{
this.res=res;
}
public void run() {
while(true)
{
res.out();
}
}
}
public class ProducerConsumer {
public static void main(String[] args) {
//建立资源;
Resource1 r = new Resource1();
//建立两个消费者线程和两个生产者线程
new Thread(new Producer(r)).start();
new Thread(new Producer(r)).start();
new Thread(new Consumer(r)).start();
new Thread(new Consumer(r)).start();
}
}
java 1.5中提供了多线程的升级解决方案;
将同步synchronized替换为现实lock操作;
将object中的wait,notify,notifyAll,替换了Condition对象;
该对象可以Lock锁,进行获取;java 1.5中提供了多线程的升级解决方案;
将同步synchronized替换为现实lock操作;
将object中的wait,notify,notifyAll,替换了Condition对象;
该对象可以Lock锁,进行获取;
实现只唤醒对方线程。
package day04;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Resource1 {
private String name;
private int count = 1;
boolean flag=false;
//多态实现,建立lock的子类对象
private Lock lock = new ReentrantLock();
//创建Condition对象,分别控制等待或唤醒对方线程
Condition condition_pro=lock.newCondition();
Condition condition_con=lock.newCondition();
public void set(String name) throws InterruptedException {
lock.lock();
try{
while(flag)//使用while判断,让被唤醒的线程再一次判断标记
condition_pro.await();
this.name =name+"----"+count++;
System.out.println(Thread.currentThread().getName()+"--生产者---"+this.name);
flag=true;
condition_con.signalAll();//只唤醒对方线程
}
finally
{
lock.unlock();// 释放锁
}
}
public void out() throws InterruptedException
{
lock.lock();
try{
while(!flag)
condition_con.await();
System.out.println(Thread.currentThread().getName()+"消费者"+this.name);
flag =false;
condition_pro.signalAll();// 只唤醒对方线程
}
finally
{
lock.unlock();// 释放锁
}
}
}
//生产者
class Producer implements Runnable
{
private Resource1 res;
//初始化生产者
Producer(Resource1 res)
{
this.res=res;
}
public void run() {
while(true)
try {
res.set("商品");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// 消费者
class Consumer implements Runnable
{
private Resource1 res;
//初始化消费者
Consumer(Resource1 res)
{
this.res=res;
}
public void run() {
while(true)
{
try {
res.out();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class ProducerConsumer {
public static void main(String[] args) {
//建立资源;
Resource1 r = new Resource1();
//建立两个消费者线程和两个生产者线程
new Thread(new Producer(r)).start();
new Thread(new Producer(r)).start();
new Thread(new Consumer(r)).start();
new Thread(new Consumer(r)).start();
}
}
7.停止线程
方法:就是让run方法结束
(1)一般情况:直接控制循环结束标记,就可以结束线程
举例:
package day04;
class StopThread implements Runnable {
private boolean flag = true;
public void run() {
while (flag) {
System.out.println(Thread.currentThread().getName()
+ "---run");
}
}
//改变循环标记
public void changeFlag(){
flag=false;
}
}
public class StopThreadDemo {
public static void main(String[] args) {
StopThread st= new StopThread();
//建立两个线程
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
int num=0;
while(true)
{
if(num++==60)
{
st.changeFlag();//改变标记,run方法停止;线程停止;
break;
}
System.out.println(Thread.currentThread().getName()+"--------"+num);
}
}
}
(2)特殊情况:使用interrupt方法
该方法时结束线程的冻结状态,是线程回到运行状态中来
注意:stop方法已经过时不在使用;
package day04;
class StopThread implements Runnable {
private boolean flag = true;
public synchronized void run() {
while (flag) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
flag =false;
}
System.out.println(Thread.currentThread().getName()
+ "---run");
}
}
//改变循环标记
public void changeFlag(){
flag=false;
}
}
public class StopThreadDemo {
public static void main(String[] args) {
StopThread st= new StopThread();
//建立两个线程
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
int num=0;
while(true)
{
if(num++==60)
{
t1.interrupt();
t2.interrupt();
//st.changeFlag();//改变标记,run方法停止;线程停止;
break;
}
System.out.println(Thread.currentThread().getName()+"--------"+num);
}
}
}
8.守护线程:前台线程结束,后台线程自动结束,守护线程就是后台线程。
package day04;
class StopThread implements Runnable {
private boolean flag = true;
public synchronized void run() {
while (flag) {
/*try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
//flag =false;
}*/
System.out.println(Thread.currentThread().getName()
+ "---run");
}
}
//改变循环标记
public void changeFlag(){
flag=false;
}
}
public class StopThreadDemo {
public static void main(String[] args) {
StopThread st= new StopThread();
//建立两个线程
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
//把两个线程设成守护线程,主线程结束,守护线程自动结束
t1.setDaemon(true);
t2.setDaemon(true);
t1.start();
t2.start();
/*
int num=0;
while(true)
{
if(num++==60)
{
//t1.interrupt();
t2.interrupt();
st.changeFlag();//改变标记,run方法停止;线程停止;
break;
}
System.out.println(Thread.currentThread().getName()+"--------"+num);
}*/
System.out.println("over");
}
}
9.oin()方法;
我们可以临时加入一个线程,让这个线程运行完,主线程放弃执行权,等到这个线程执行完,才获得执行权;
join:当A线程执行到了B线程的join方法时,A线程就会等待,等B线程执行完,A才会执行。
join可以用来临时加入线程执行。
yield暂停当前执行的线程,并执行其他线程;
10.开发写线程:某些代码需要被同时执行时,就用单独的线程进行封装;
package one;
public class ThreadTest {
public static void main(String args[]) {
new Thread() {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "..."
+ i);
}
}
}.start();
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "..." + i);
}
Runnable a= new Runnable() {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "..." + i);
}
}
};
new Thread(a).start();
}
}