[javase]多线程(一)

学习JAVA编程思想第二十一章-并发

编写火箭10秒倒数发射线程类,该类实现runnable接口。

技术点:

1、Thread.yeid() 和 Thread.sleep() 的区别?

Thread.yeid() 线程的调度(让步),暂停当前正在执行的线程对象,并执行其他线程。(注意:这里的其他也包含当前线程)

Thread.sleep() 使当前线程暂停millis所指定的毫秒,转到执行其它线程。

package com.javanet.thread;
/**
 * 多线程
 * 定时任务 火箭倒数10秒发射实例
 */
public class ListOff implements Runnable {
	
	//倒数计时
	protected int countDown = 10;
	//线程任务计数器 默认值0
	private static int taskCount = 0;
	//线程任务
	private final int id = taskCount++;
	

	public ListOff() {
	}
	
	public ListOff(int countDown) {
		this.countDown = countDown;
	}

	public String status() {
		return "#"+id+"("+(countDown > 0 ? countDown : "ListOff!")+"), ";
	}
	
	@Override
	public void run() {
		
		while (countDown-- > 0) {
			
			System.out.print(status());
			Thread.yield();
			
		}
	}

}

执行定时任务类

/**
 * 将runnable对象变为工作任务的传统方式:
 * 		提交给Thread构造器
 */
@Test
public void test1() {
	
	Thread t = new Thread(new ListOff());
	t.start();
	System.out.println("Waiting for ListOff!");
}

/**
 * 添加5个任务启动工作任务
 */
@Test
public void test2() {

	for (int i = 0; i < 5; i++) {
		
		new Thread(new ListOff()).start();
	}
	System.out.println("Waiting for ListOff!");
	
}

执行结果:

//执行test1()结果
Waiting for ListOff!
#0(9), #0(8), #0(7), #0(6), #0(5), #0(4), #0(3), #0(2), #0(1), #0(ListOff!),  
//执行test2()结果
Waiting for ListOff!
#3(9), #1(9), #4(9), #2(9), #0(9), #3(8), #1(8), #4(8), #2(8), #0(8), #3(7), #4(7), #1(7), #2(7), #0(7), #4(6), #1(6), #3(6), #2(6), #0(6), #4(5), #1(5), #3(5), #2(5), #0(5), #4(4), #1(4), #3(4), #2(4), #0(4), #4(3), #1(3), #3(3), #2(3), #0(3), #4(2), #1(2), #3(2), #2(2), #0(2), #4(1), #1(1), #3(1), #2(1), #0(1), #1(ListOff!), #3(ListOff!), #4(ListOff!), #2(ListOff!), 

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">输出说明不同任务的执行在线程被换进换出时混在一起。这种交换是由线程调度器自动控制的。如果在你的机器上有多个处理器,线程调度器将会在这些处理器之间默默的分发线程。</span>

使用Executor
Executor框架是指java 5中引入的一系列并发库中与executor相关的一些功能类,其中包括线程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable等。他们的关系为:


并发编程的一种编程方式是把任务拆分为一些列的小任务,即Runnable,然后在提交给一个Executor执行,Executor.execute(Runnalbe) 。Executor在执行时使用内部的线程池完成操作。

Executors类,提供了一系列工厂方法用于创先线程池,返回的线程池都实现了ExecutorService接口。

public static ExecutorService newFixedThreadPool(int nThreads)

创建固定数目线程的线程池。

/**
 * 创建固定数量的线程池
 */
@Test
public void test3() {
	
	ExecutorService es = Executors.newFixedThreadPool(5);
	for (int i = 0; i < 5; i++) {
		es.execute(new ListOff());
	}
	es.shutdown();

}

#2(9), #1(9), #4(9), #3(9), #0(9), #2(8), #1(8), #3(8), #4(8), #0(8), #2(7), #0(7), #4(7), #3(7), #1(7), #0(6), #4(6), #3(6), #2(6), #1(6), #0(5), #4(5), #3(5), #2(5), #1(5), #0(4), #4(4), #3(4), #2(4), #0(3), #1(4), #4(3), #3(3), #2(3), #0(2), #1(3), #4(2), #0(1), #2(2), #3(2), #1(2), #4(1), #0(ListOff!), #2(1), #3(1), #1(1), #4(ListOff!), #2(ListOff!), #3(ListOff!), #1(ListOff!), 

public static ExecutorService newCachedThreadPool()

创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。

有了FixedThreadPool,你就可以一次性预先执行代价高昂的线程分配,因而也就可以限制线程的数量了。这可以节省时间,因为你不用为每个任务都固定创建线程的开销

@Test
public void test4() {
	
	ExecutorService es = Executors.newCachedThreadPool();
	for (int i = 0; i < 5; i++) {
		es.execute(new ListOff());
	}
	es.shutdown();
}
#3(9), #0(9), #1(9), #4(9), #2(9), #3(8), #0(8), #1(8), #4(8), #2(8), #3(7), #0(7), #1(7), #4(7), #2(7), #3(6), #0(6), #1(6), #4(6), #2(6), #3(5), #0(5), #1(5), #4(5), #2(5), #3(4), #0(4), #1(4), #4(4), #2(4), #3(3), #0(3), #4(3), #1(3), #2(3), #3(2), #0(2), #4(2), #1(2), #2(2), #3(1), #0(1), #4(1), #1(1), #2(1), #3(ListOff!), #0(ListOff!), #4(ListOff!), #1(ListOff!), #2(ListOff!), 

CachedThreadPool在程序执行过程中通常会创建与所需数量相同的线程,然后在它回收旧线程时停止创建新线程,因此它合理的Executor首选。只有当这种方式会引发问题时候,你才需要切换到FixedThreadPool。

public static ExecutorService newSingleThreadExecutor()

创建一个单线程化的Executor

1、SingleThreadExecutor就像线程为1的FixedThreadPool

2、如果向SingleThreadExecutor提交多个任务,这些任务将排队。从输出结果可以看到,任务按照提交顺序被执行。

3、SingleThreadExecutor会序列化所有提交的任务,并维护自己(隐藏)的悬挂任务队列。

4、SingleThreadExecutor可以确保任何线程中都只有唯一的任务在运行。(多个线程使用同一文件系统时,可以用SingleThreadExecutor来保持同步)

/**
 * SingleThreadExecutor
 */
@Test
public void test5() {
	
	ExecutorService es = Executors.newSingleThreadExecutor();
	for (int i = 0; i < 5; i++) {
		es.execute(new ListOff());
	}
	es.shutdown();
	
}
#0(9), #0(8), #0(7), #0(6), #0(5), #0(4), #0(3), #0(2), #0(1), #0(ListOff!), #1(9), #1(8), #1(7), #1(6), #1(5), #1(4), #1(3), #1(2), #1(1), #1(ListOff!), #2(9), #2(8), #2(7), #2(6), #2(5), #2(4), #2(3), #2(2), #2(1), #2(ListOff!), #3(9), #3(8), #3(7), #3(6), #3(5), #3(4), #3(3), #3(2), #3(1), #3(ListOff!), #4(9), #4(8), #4(7), #4(6), #4(5), #4(4), #4(3), #4(2), #4(1), #4(ListOff!), 

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。

/**
 * scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnitunit)
 * 
 * 创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期;
 * 也就是将在 initialDelay 后开始执行,
 * 然后在initialDelay+period 后执行,
 * 接着在 initialDelay + 2 * period 后执行,依此类推。
 * 
 * 下面例子:
 * 创建beeper定时任务,0秒开始执行,每隔10秒再执行一次,直到1*60秒后取消定时任务
 */
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
public void beepForAnHour() {
	final Runnable beeper = new Runnable() {
		public void run() {
			System.out.println("beep");
		}
	};
	
	final ScheduledFuture<?> beeperHandle = scheduler.<span style="color:#ff0000;">scheduleAtFixedRate</span>(beeper, 0, 10, TimeUnit.SECONDS);
	scheduler.schedule(new Runnable() {
		public void run() {
			beeperHandle.cancel(true);
		}
	}, 1 * 60, TimeUnit.SECONDS);
}

public static void main(String[] args) {
	new TestThread().beepForAnHour();
}
beep
beep
beep
beep
beep
beep
beep

final ScheduledExecutorService exec = Executors.newScheduledThreadPool(1);
/**
 * 创建并执行在给定延迟后启用的一次性操作。
 */
exec.<span style="color:#ff0000;">schedule</span>(new Runnable() {
    public void run() {
        System.out.println("The thread can only run once!");
    }
},5000,TimeUnit.MILLISECONDS);
/**
 * 创建并执行一个在给定初始延迟后首次启用的定期操作,<br/>
 * 随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟。
 */
exec.<span style="color:#ff0000;">scheduleWithFixedDelay</span>(new Runnable() {
    public void run() {
        System.out.println("scheduleWithFixedDelay:begin,"+format.format(new Date()));
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("scheduleWithFixedDelay:end,"+format.format(new Date()));
    }
},1000,5000,TimeUnit.MILLISECONDS);

注意:

1、开始执行后就触发异常,next周期将不会运行。解决办法是抛出所有可能的异常,当被拦截了,next周期继续运行。

2、scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) 和scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) 的区别很明显,主要区别在第三个参数上面。

它们不同的是前者以固定频率执行,后者以相对固定频率执行。
前者表示 程序启动initialDelay秒后执行command,period秒后再次执行command,不管command任务有没有执行完成。

后者表示 程序启动initialDelay秒后执行command,当command执行完毕,等待delay秒后,再次执行。

从任务中产生返回值

package com.javanet.thread;

import java.util.concurrent.Callable;
/**
 * 带返回值的多线程接口
 */
public class TaskWithResult implements Callable<String> {
	
	private int id;
	
	public TaskWithResult(int id) {
		this.id = id;
	}
	
	@Override
	public String call() throws Exception {
		
		return "result of taskWithResult: " + id;
	}

}
package com.javanet.thread;

import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class CallableDemo {
	
	public static void main(String[] args) {
		
		ExecutorService exec = Executors.newCachedThreadPool();
		ArrayList<Future<String>> results = new ArrayList<Future<String>>();
		for (int i = 0; i < 10; i++) {
			Future<String> submit = exec.submit(new TaskWithResult(i));
			if (submit.isDone()) {
				results.add(submit);
			}
		}
		
		for (Future<String> future : results) {
			try {
				System.out.println(future.get());
			} catch (InterruptedException e) {
				e.printStackTrace();
				return;
			} catch (ExecutionException e) {
				e.printStackTrace();
			} finally {
				exec.shutdown();
			}
		}
		
	}
}
执行结果
result of taskWithResult: 0
result of taskWithResult: 1
result of taskWithResult: 2
result of taskWithResult: 3
result of taskWithResult: 4
result of taskWithResult: 5
result of taskWithResult: 6
result of taskWithResult: 7
result of taskWithResult: 8
result of taskWithResult: 9
休眠 sleep

package com.javanet.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class SleepTask extends ListOff {
	
	@Override
	public void run() {
		
		try {
			while (countDown-- > 0) {
				
				System.out.print(status());
					TimeUnit.MILLISECONDS.sleep(100);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}
	
	public static void main(String[] args) {
		
		ExecutorService exec = Executors.newCachedThreadPool();
		for (int i = 0; i < 5; i++) {
			
			exec.execute(new SleepTask());
			
		}
		exec.shutdown();
		
	}
}
执行结果
#3(9), #2(9), #1(9), #4(9), #0(9), #0(8), #4(8), #1(8), #3(8), #2(8), #2(7), #3(7), #0(7), #1(7), #4(7), #3(6), #1(6), #4(6), #0(6), #2(6), #0(5), #1(5), #2(5), #4(5), #3(5), #0(4), #4(4), #1(4), #2(4), #3(4), #3(3), #0(3), #2(3), #1(3), #4(3), #1(2), #3(2), #4(2), #2(2), #0(2), #2(1), #1(1), #4(1), #0(1), #3(1), #3(ListOff!), #1(ListOff!), #0(ListOff!), #2(ListOff!), #4(ListOff!), 

优先级

package com.javanet.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/** 
* 优先级 
*/
public class SimplePriorities implements Runnable {
	
	private int countDown = 5;
	private volatile double d;
	private int priority;
	
	public SimplePriorities(int priority) {
		this.priority = priority;
	}
	
	public String toString() {
		return Thread.currentThread() + ": " + countDown;
	}

	@Override
	public void run() {
		//设置当前线程的优先级
		Thread.currentThread().setPriority(priority);
		while (true) {
			for (int i = 0; i < 100000; i++) {
				d += (Math.PI + Math.E) / (double) i;
				if (i % 1000 == 0) {
					Thread.yield();
				}
				System.out.println(this);
				if (--countDown == 0) return;
			}
		}
	}
	
	public static void main(String[] args) {
		
		ExecutorService exec = Executors.newCachedThreadPool();
		for (int i = 0; i < 5; i++) {
			exec.execute(new SimplePriorities(Thread.MIN_PRIORITY));
		}
		exec.execute(new SimplePriorities(Thread.MAX_PRIORITY));
		exec.shutdown();
	}
	
	
}
执行结果

Thread[pool-1-thread-2,1,main]: 5
Thread[pool-1-thread-5,1,main]: 5
Thread[pool-1-thread-5,1,main]: 4
Thread[pool-1-thread-2,1,main]: 4
Thread[pool-1-thread-3,1,main]: 5
Thread[pool-1-thread-4,1,main]: 5
Thread[pool-1-thread-6,10,main]: 5
Thread[pool-1-thread-1,1,main]: 5
Thread[pool-1-thread-6,10,main]: 4
Thread[pool-1-thread-4,1,main]: 4
Thread[pool-1-thread-3,1,main]: 4
Thread[pool-1-thread-2,1,main]: 3
Thread[pool-1-thread-5,1,main]: 3
Thread[pool-1-thread-2,1,main]: 2
Thread[pool-1-thread-3,1,main]: 3
Thread[pool-1-thread-4,1,main]: 3
Thread[pool-1-thread-6,10,main]: 3
Thread[pool-1-thread-1,1,main]: 4
Thread[pool-1-thread-6,10,main]: 2
Thread[pool-1-thread-4,1,main]: 2
Thread[pool-1-thread-3,1,main]: 2
Thread[pool-1-thread-2,1,main]: 1
Thread[pool-1-thread-5,1,main]: 2
Thread[pool-1-thread-5,1,main]: 1
Thread[pool-1-thread-3,1,main]: 1
Thread[pool-1-thread-4,1,main]: 1
Thread[pool-1-thread-6,10,main]: 1
Thread[pool-1-thread-1,1,main]: 3
Thread[pool-1-thread-1,1,main]: 2
Thread[pool-1-thread-1,1,main]: 1
让步yied()

后台线程

所谓后台(daemon)线程,也叫守护线程。是指在程序运行的时候再后台提供一种通用服务的线程,并且这种线程并不属于程序中不可或缺的部分。因此,当所有的非后台线程结束时,程序也就终止了,同时会杀死进程中的所有后台线程。反过来,只要有任何非后台线程还在运行,程序就不会终止。比如,执行main()就是一个非后台线程。

在线程启动之前调用setDaemon()方法,就能把线程设为后台线程

在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程) 

只要当前JVM实例中尚存在任何一个用户线程没有结束,守护线程就全部工作;只有当最后一个用户线程结束时,守护线程随着JVM一同结束工作。

package com.javanet.thread;

import java.util.concurrent.TimeUnit;

/** 
 * 后台线程
*/
public class SimpleDaemons implements Runnable{

	@Override
	public void run() {
		
		try {
			while (true) {
				TimeUnit.MILLISECONDS.sleep(100);
				System.out.println(Thread.currentThread() + "" + this);
			}
		} catch (Exception e) {
			System.out.println("sleep() interrupted");
		}
	}
	
	public static void main(String[] args) throws InterruptedException {
		for (int i = 0; i < 10; i++) {
			Thread daemon = new Thread(new SimpleDaemons());
			daemon.setDaemon(true);
			daemon.start();
		}
		System.out.println("All daemons started");
		TimeUnit.MILLISECONDS.sleep(100);
	}
	
}
编码的变体

1、继承Thread类方式

package com.javanet.thread;
/** 
 * 继承thread
*/
public class SimpleThread extends Thread {
	
	private int countDown = 5;
	private static int threadCount = 0;
	
	public SimpleThread() {
		start();
	}
	
	public String toString() {
		return "#" + getName() + "(" + countDown +"), ";
	}
	
	@Override
	public void run() {
		while (true) {
			System.out.print(this);
			if (--countDown == 0) {
				return;
			}
		}
	}
	
	public static void main(String[] args) {
		for (int i = 0; i < 5; i++) {
			new SimpleThread();
		}
	}
	
	//执行结果:#Thread-0(5), #Thread-1(5), #Thread-2(5), #Thread-0(4), #Thread-2(4), #Thread-1(4), #Thread-4(5), #Thread-1(3), #Thread-4(4), #Thread-4(3), #Thread-2(3), #Thread-3(5), #Thread-0(3), #Thread-3(4), #Thread-2(2), #Thread-4(2), #Thread-1(2), #Thread-4(1), #Thread-2(1), #Thread-3(3), #Thread-0(2), #Thread-3(2), #Thread-3(1), #Thread-1(1), #Thread-0(1), 
}

2、资管理runnable

package com.javanet.thread;
/** 
 * 自管理
*/
public class SelfManaged implements Runnable {
	
	private int countDown = 5;
	private Thread t = new Thread(this);
	
	public SelfManaged() {
		t.start();
	}
	
	public String toString() {
		return Thread.currentThread().getName() + "(" + countDown +"), ";
	}
	
	@Override
	public void run() {
		while (true) {
			System.out.print(this);
			if (--countDown == 0) {
				return;
			}
		}
	}
	
	public static void main(String[] args) {
		for (int i = 0; i < 5; i++) {
			new SelfManaged();
		}
	}
}

3、内部类方式将线程代码隐藏在类中

package com.javanet.thread;
/** 
 * 内部类
*/
public class InnerThread1 {
	
	private int countDown = 5;
	private Inner inner;
	
	public InnerThread1(String name) {
		inner = new Inner(name);
	}
	
	class Inner extends Thread {
		
		public Inner(String name) {
			super(name);
			start();
		}
		
		@Override
		public void run() {
			try {
				while (true) {
					System.out.println(this);
					if (--countDown == 0) {
						return;
					}
				}
			} catch (Exception e) {
			}
		}
		
		@Override
		public String toString() {
			return getName()+": " + countDown;
		}
		
	}
	
	public static void main(String[] args) {
		new InnerThread1("小明");
	}
	
	/**
	 * 执行结果
	 *  小明: 5
		小明: 4
		小明: 3
		小明: 2
		小明: 1
	 */
}

未完待续

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值