多线程

一、线程概念

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();
		

	}
}


 


 



 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值