多线程总结


黑马程序员

       ----------------------android培训java培训 、期待与您交流! ----------------------

 

线程:正在进行中的程序。每一个进程执行都有一个执行的顺序。该顺序就是一个执行路径,或者叫一个控制单元。线程就是进程中的一个独立单元,线程控制着进程的执行,一个进程中至少有一个线程。

特点:线程是程序中的控制单元或者叫执行路径。

Java vm启动时候会有一个进程java.exe,该进程至少有一个线程负责java程序的执行,而且这个线程运行的代码存在于main方法中。该线程称之为主线程。

创建线程的第一种方式:继承Thread

步骤:1,定义类继承Thread

        2,复写Thread中的Run方法

            目地:将自定义的代码块存储在Run方法中,让线程运行。

        3,调用线程的Start方法,该法有两个作用,第一个是启动线程,第二个是调动Run方法。

发现运行结果的没一次都不同,因为多个线程都获取CPU的执行权,CPU到底执行谁,运行谁。明确一点,在某一个时刻,只能有一个程序在运行。(多核除外)CPU在做着快速的切换,以达到看上去是同时运行的效果。我们可以形象把多线程的运行行为在互相抢夺CPU的执行权。

这就是多线程的一个特点:随机性。谁抢到谁执行,至于执行多长,CPU说的算。

Demo d=new Demo();创建好一个线程

d.Start();开启线程并执行该线程的Run方法

d.run();仅仅是对象调用方法,而线程创建了,并没有运行。

没有执行资格的情况下就是冻结状态。

有执行资格的就是临时状态。

既有资格又有执行权的就是运行状态。

Static Thread CurrentThread();获取当前对象。

getName();获取当前线程的名称。

设置线程名称:setName或者构造函数。

使用static可以共享一个线程(一般不用)

实现线程的步骤

   1 、实现Runnable接口

2、覆盖Runnable接口的Rund方法

    将线程要运行的代码放在该Run方法中。

3、通过Thread类建立线程对象。

4、将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数

         为什么要将Runnable接口中的子类对象传递给Thread类的构造函数。因为,自定义的Run方法所属的对象是Runnable接口子类的对象。

所以要让线程执行指定对象的Run方法。就必须明确该Run方法所属的对象。

5、调用Thread类的start方法开启线程并调用Runable接口子类的Run方法

 

线程实现方式和继承方式有什么区别呢?

实现的好处:是避免了单继承的局限性.

在定义线程的时候,建立使用实现方式。

两种方式区别:

继承Thread:线程代码存放在Thread子类Run方法中。

实现Runnable,线程代码存在接口的子类Run方法中

同步:A线程要请求某个资源,但是此资源正在被B资源使用,因为同步机制的存在,A线程请求不到,怎么办,A只能等待下去。

异步:A线程要请求某个资源,但是此资源正在被B线程使用,因为没有同步机制的存在,A线程任然请求的到,A线程无需等待。

 

 

死锁:就是说,你持有一个锁,我也持有一个锁,我要到你里面运行,你要到我里面,你不放你的锁要到我里面去,我不放我的锁要到你里面去。

同步中嵌套同步。

同步函数用的哪一个锁呢?函数需要被对象调用。那么函数都要有一个所属对象引用。就是this所以同步函数使用的锁是this 通过该程序进行验证。

  使用两个线程来买票。一个线程在同步代码块中。一个程序在同步函数中。都在执行买票动作。

  如果同步函数被静态修饰后,使用的锁是什么呢?

 通过验证,发现不在是this.因为静态方法也不可以定义this.

态进内存是,内存中没有本类对象,但是一定有该类对应的字节码文件对象。

 类名.class 该对象的类型是class

 

 静态的同步方法,使用的锁是该方法所在类的字节码文件对象。

 

public class Ticket2 {
	public static void main(String[] args) {
	
		TciktDemos tc = new TciktDemos();
		Thread t1 = new Thread(tc);
		Thread t2 = new Thread(tc);
		t1.start();
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		tc.flag=false;
		t2.start();

	}

}

class TciktDemos implements Runnable {
	private int tick = 100;
	//Object obj = new Object();
	boolean flag=true;
	public void run() {
		
		if(flag){
			while (true) {
				synchronized (this) {
					if (tick > 0) {
						try {
							Thread.sleep(10);
							System.out.println(Thread.currentThread().getName()
								+ ".....code:" + tick--);
							}catch(InterruptedException e) {
								e.printStackTrace();
							} 
					}
				}
			}
		}else
			while(true)
			this.show();

	}

	public synchronized void show() {
		if (tick > 0) {
			try {
				Thread.sleep(10);
				System.out.println(Thread.currentThread().getName()
						+ ".....show...:" + tick--);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}

}

死锁代码块:

public class DeadLockTest {
	
	public static void main(String[] args) {

		Thread t1=new Thread(new test(true));
		Thread t2=new Thread(new test(false));
		t1.start();
		t2.start();
	}

	
}

class test implements Runnable{
	private boolean flag;
	
	test(boolean flag){
		this.flag=flag;
		
	}

	public void run() {
		if(flag){
			while(true){
			synchronized (MyLock.locka) {
				
					System.out.println("if locka");
				
				synchronized (MyLock.lockb) {
					
					System.out.println("if lockb");
				}
				
			}
			}
			
		}else{
			while(true){
			synchronized (MyLock.lockb) {
				
					System.out.println("else lockb");
					
				synchronized (MyLock.locka) {
					
					System.out.println("else locka");
					
				}
				
			}
			
			}
		}
		
	}
	
}

class MyLock{
	
	static Object locka=new Object();
	static Object lockb=new Object();
	
	
}


 

 单列设计模式:
  class Single{
     private static final Single s=new Single();
     private Single(){
     }
     public static Single  getInstance(){
     
     		return s;
     }
  
  }
懒汉式与饿汉式有什么不同?
懒汉式的特点在于延迟加载, 懒汉式延迟加载有没有问题,有
怎么解决,加同步的方式解决,用同步代码块和同步函数都行,但是稍微有些低效。
双重判断可以解决效率问题,加同步的时候,使用的锁是那个该类所属的字节码对象。 
 
 */
class Single{
	//懒汉式 ,在多线程访问下会出现安全隐患。懒汉式加了同步会比较低效 
	private  static  Single s=null;
	
	private	Single(){
		
	}
	
	/*
	 	延迟加载,对象被延迟
		s是共享数据,如果多个线程并发访问getInstance,是有可能的!
		 
	 */
	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) {
		
	}
	
	
	

}
/*
 线程通讯:
其实就是多个线程在操作同一个资源。
但是操作的动作不同。

wait:
notify();
notifyAll();

都是用在同步中,因为要对持有监视器(锁)的线程操作。
所以在使用同步中,因为只有同步才具有锁的概率。
为什么这些操作线程的方法要定义在Object类中呢?
因为这些方法在操作同步线程时,都必须要标示他们所操作线程只有的锁,只有同一个
锁上的被等待线程,可以被同一锁上的notify唤醒。
不可以对不同锁中的线程进行唤醒
也就是说,等待和唤醒必须是同一个锁,而锁可以是任意对象,所以可以被任意对象调用调用的方法定义Object类中。
 */
class Res2{
	
	private String name;
	private String sex;
	private boolean flag=false;
	
	public synchronized void set(String name,String sex){
		
			if(flag)
				try {
						
					this.wait();
				}
				catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				this.name=name;
				this.sex=sex;
				flag=true;
				this.notify();
		
			
	}
	
	public synchronized void out(){
			if(!flag)
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(name+"........"+sex);
			this.flag=false;
			this.notify();
	}
			
}

class  Input2 implements Runnable{
	private Res2 r;
	
	Input2(Res2 r){
		
		this.r=r;
	}
	
	public void run() {
		int x=0;
		while(true){
			if(x==0){
				r.set("mike", "man");
						
			}else{
						
				r.set("莉莉", "女女女女女");
			}
			x=(x+1)%2;
		} 
				
			
	}
}

class Output2 implements Runnable{
	private Res2 r;
	
	Output2(Res2 r){
		
		this.r=r; 
	}
	
	public void run() {
		
		while(true){
			r.out();
		}
	}
	
	
	
}
public class InpntOutputDemo2 {
	
	public static void main(String[] args) {
		Res2 r=new Res2();
		new Thread(new Input2(r)).start();
		new Thread(new Output2(r)).start();
	}

}
public class ProducerConsumerDemo2 {
	
	public static void main(String[] args) {
		Resource res=new Resource();
		
		Producer pro=new Producer(res);
		Consumer con=new Consumer(res);
		Thread t1=new Thread(pro);
		Thread t2=new Thread(pro);
		Thread t3=new Thread(con);
		Thread t4=new Thread(con);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}

}


 

/*
JDK1.5中提供了多线程升级解决方案。
将同步中synchronized替换成现实lock操作。
将object中的wait,notify,notifyAll,替换了Condition对象。
该对象可以通过Lock锁获取。
1.5的新特性实现了Lock接口和Condition接口。
该实例中实现了本方只唤醒对方的操作。

1.5版本后,提供了显示的锁机制,以及显示的锁对象上的等待唤醒操作机制,同封装了等待唤醒。一个锁可以对应
多个Condition。
	
 */
class Resources{
	private String name;
	private int count=1;
	private boolean flag=false;
	private Lock lock=new ReentrantLock();
	
	private Condition condition_pro=lock.newCondition();
	private Condition condition_con=lock.newCondition();
	
	public synchronized void set(String name){
		lock.lock();
		try{
		while(flag)
		condition_pro.wait();//t1 t2
		this.name=name+"....."+count++;
		System.out.println(Thread.currentThread().getName()+".....生产者....."+this.name);
		this.flag=true;
		condition_con.signalAll();
		}catch(Exception ex){
			ex.printStackTrace();
		}finally{
			lock.unlock();//释放一次解锁动作。
		}
		
	}
	
	public synchronized void out(){
		lock.lock();
		try{
		while(!flag)
		condition_con.wait();
		System.out.println(Thread.currentThread().getName()+".....消费者.............."+this.name);
		this.flag=false;
		condition_pro.signalAll();
		}catch(Exception ex){
			ex.printStackTrace();
		}finally{
			lock.unlock();
		}
	}
	
	
	
}


class Producers implements Runnable{
	
	private	Resources  res;

	Producers(Resources  res){
		this.res=res;
	}
	public void run() {
		while(true){
			
			res.set("商品");
			
		}
		
	}
}

class Consumers implements Runnable{
	

	private	Resources  res;

	Consumers(Resources  res){
		this.res=res;
	}
	public void run() {
		while(true){
			
			res.out();
			
		}
		
	}
	
}

                    

 

/*

stop停止方法已过时。
如何停止线程。
只有一种,run方法结束。
开启多线程运行,运行代码通常是循环结构。
只要控制住循环,就可以让run方法结束,也就是线程结束。

特性情况:
当线程处于了冻结状态、
就不会读取标记,那么线程就不会结束。

当没有指定的方式让冻结的线程恢复到运行状态是,这时需要对冻结进行清除。
强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。
Thread类提供该方法interrupt()
 */
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){
				//st.changeFlag();
				t1.interrupt(); 
				t2.interrupt();
				break;
			}
			System.out.println(Thread.currentThread().getName()+"main......."+num);
		}
		System.out.println("over");
	}



}

class StopThread implements Runnable{
	private boolean flag=true;
	public synchronized void run() {
		while(flag){
			try {
				wait();
			} catch (InterruptedException e) {
				System.out.println(Thread.currentThread().getName()+".....Execption");
				flag=false;
			}
			System.out.println(Thread.currentThread().getName()+".....run");
		}
		
	}
	
	public void changeFlag(){
		flag=false;
	}

	
}


                                                         

 

                                                                                 ----------------------android培训java培训、期待与您交流! ------------------

详细请查看:http://edu.csdn.net/heima

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值