多线程以及wait notify synchronization Future概念及理解

对于多线程的理解

操作系统中有进程和线程两个相似的概念,其中

 

进程:每个进程都有独立的代码和数据空间,进程间切换会有较大的开销,进程是资源分配的最小单位

线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器,线程切换开销小,线程是cpu调度的最小单位

五个阶段:创建(New),就绪(Runnable),运行(Running),阻塞(Blocked),终止(Dead)

多进程是操作系统能同时运行多个任务

多进程是同一程序中有多个顺序流在执行

 

 

java实现多线程可通过继承Thread类,或者重写Runnable接口,或者实现Callable接口并与Future、线程池来实现。如果继承Thread则不适合资源共享,如果实现了Runable接口能很容易实现资源共享(适合多个线程去处理同一个资源,避免单继承的限制)

 

java的进程同步通过synchronized()实现,他通过对内存加锁使其他线程无法访问该内存实现简单的同步,互斥操作

而通过Object.wait(), Object.nofity()则可以实现线程间相互唤醒。

例如,连续交替打印十次ABC。

package ceshi;

public class Main {
	static class My implements Runnable
	{
		private String name;
		private Object prev;
		private Object self;
		
		private My(String name, Object prev, Object self)
		{
			this.name = name;
			this.prev = prev;
			this.self = self;
		}
		public void run()
		{
			int count = 10;
			while(count>0)
			{
				synchronized(prev)
				{
					synchronized(self)
					{
						System.out.print(name);
						count--;
						self.notify();//释放自身对象锁
					}
					try 
					{
						prev.wait();//释放prev对象锁
					}catch(InterruptedException e)
					{
						e.printStackTrace();
					}
				}
			}
		}
	}
	public static void main(String[]args)throws Exception
	{
		Object a = new Object();
		Object b = new Object();
		Object c = new Object();
		Object d = new Object();
		My pa = new My("A", d, a);
		My pb = new My("B", a, b);	
		My pc = new My("C", b, c);
		My pd = new My("D", c, d);
		
		new Thread(pa).start();
		System.out.println("aaaaaa");
		new Thread(pb).start();
		System.out.println("bbbbbb");
		new Thread(pc).start();
		System.out.println("cccccc");
		new Thread(pd).start();
		System.out.println("dddddd");
	}
}

输出为

可见程序的运行顺序是依次打开pa,pb,pc,pd然后循环进行

 

 

 

修改一下,核心代码变成这样以后

                        while(count>0)
			{
				synchronized(prev)
				{
					synchronized(self)
					{
						System.out.print(name);
						count--;
						try
						{
							Thread.sleep(1);
						}catch(InterruptedException e)
						{
							e.printStackTrace();
						}
						self.notify();
					}
					try 
					{
						prev.wait();
					}catch(InterruptedException e)
					{
						e.printStackTrace();
					}
				}
			}

输出仍然不正确,结果为

这是由于JVM调度的不确定性,需要让ABCD按照确定的顺序启动

                new Thread(pa).start();
		Thread.sleep(10);
		new Thread(pb).start();
		Thread.sleep(10);
		new Thread(pc).start();
		Thread.sleep(10);
		new Thread(pd).start();
		Thread.sleep(10);

每次启动一个线程以后,令其休眠,且休眠时间长于释放自身对象锁和prev对象锁的时间,则能够保证程序按照要求的顺序进行。

start()方法的调用后并不是立即执行多线程代码,而是使得该线程变为可运行态(Runnable),什么时候运行是由操作系统决定的,Thread.sleep()方法调用目的是不让当前线程独自霸占该进程所获取的CPU资源,以留出一定时间给其他线程执行的机会。多线程的代码执行顺序是不确定的,执行的结果也是随机的。

线程状态转换

先new Thread,然后start使线程变成可运行态,先抢到cpu资源的线程开始运行,synchronized的线程对内存加锁获得独占访问,然后sleep.wait或者被其他线程占用的线程将进入阻塞状态,等到重新到达可运行态才有机会被运行

java线程具有优先级,用setPriority()和getPriority()方法分别用来设置和获取线程的优先级,其中分配给线程的默认优先级为5,最低为1,最高为10;

常用函数:

1.线程睡眠 Thread.sleep(long millis)方法使线程转到阻塞状态,设定的时间结束后转为Runnable,sleep平台移植性好

2.线程等待:Object的wait方法导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 唤醒方法。

3.线程让步:Thread.yield方法暂停当前线程,把执行机会让给相同或优先级更高的线程

4.线程加入:join方法,在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。

5.线程唤醒:Object中的notify方法,唤醒等待的单个线程

 

Future

Future是一个未来对象,里面保存这线程处理结果,通过实现Callback接口,并用Future可以来接收多线程的执行结果。        Future表示一个可能还没有完成的异步任务的结果,针对这个结果可以添加Callback以便在任务执行成功或失败后作出相应的操作。

它可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。

cancel方法用来取消任务

isCancelled方法表示任务是否被取消成功

isDone方法表示任务是否已经完成

get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null

举个栗子:买包子(3秒)和凉菜(1秒)

普通多线程需要4秒

package ceshi;

public class Main {
	
	static class Bao extends Thread
	{
		public void run()
		{
			try
			{
				Thread.sleep(1000*3);
				System.out.println("包子做好了");
			}catch(InterruptedException e)
			{
				e.printStackTrace();
			}
		}
	}
	static class Liang extends Thread
	{
		public void run()
		{
			try
			{
				Thread.sleep(1000);
				System.out.println("凉菜做好了");
			}catch(InterruptedException e)
			{
				e.printStackTrace();
			}
		}
	}
	public static void main(String[]args)throws InterruptedException
	{
		long start = System.currentTimeMillis();
		Thread t1 = new Liang();
		t1.start();
		t1.join();
		
		Thread t2 = new Bao();
		t2.start();
		t2.join();
		
		long end = System.currentTimeMillis();
		System.out.println("总时间: "+(end-start)/1000+"秒");
	}
}

 结果是4秒

事实上只需要三秒

package ceshi;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class Main {
	
	public static void main(String[]args)throws Exception
	{
		long start = System.currentTimeMillis();
		Callable ca1 = new Callable() {
			public String call()throws Exception{
				try {
					Thread.sleep(1000);
				}catch(InterruptedException e)
				{
					e.printStackTrace();
				}
				return "凉菜做好了";
			}
		};
		FutureTask<String>ft1 = new FutureTask<String >(ca1);
		new Thread(ft1).start();
		
		Callable ca2 = new Callable()
		{
			public String call()throws Exception{
				try {
					Thread.sleep(1000*3);
				}catch(InterruptedException e)
				{
					e.printStackTrace();
				}
				return"包子做好了";
			}
		};
		FutureTask<String>ft2 = new FutureTask<String>(ca2);
		new Thread(ft2).start();
		
		System.out.println(ft1.get());
		System.out.println(ft2.get());
		
		long end = System.currentTimeMillis();
		System.out.println("总时间: "+(end - start)/1000+"秒");
 	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值