实现多线程的两种方式--Runnable和Thread/线程池import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyRunnable implements Runnable{
protected int countDown=10;
private static int taskCount=0;
private final int id = taskCount++;
public MyRunnable(){}
public MyRunnable(int countDown){
this.countDown=countDown;
}
public void run(){
while(countDown-->0){
System.out.println("#"+id+" ("+(countDown>0?countDown:"liftoff!")+")");
//告诉其他线程,让同级其他线程执行
Thread.yield();
}
}
public static void main(String[]args){
ExecutorService exe = Executors.newCachedThreadPool();
for(int i=0;i<5;i++){
//注释处也可以正常运行
// Thread t = new Thread(new MyRunnable());
// t.start();
exe.execute(new MyRunnable());
}
//如果不结束,将会一直运行,虽然没有线程了。
exe.shutdown();
}
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyRunnable implements Runnable{
protected int countDown=10;
private static int taskCount=0;
private final int id = taskCount++;
public MyRunnable(){}
public MyRunnable(int countDown){
this.countDown=countDown;
}
public void run(){
while(countDown-->0){
System.out.println("#"+id+" ("+(countDown>0?countDown:"liftoff!")+")");
//告诉其他线程,让同级其他线程执行
Thread.yield();
}
}
public static void main(String[]args){
ExecutorService exe = Executors.newCachedThreadPool();
for(int i=0;i<5;i++){
//注释处也可以正常运行
// Thread t = new Thread(new MyRunnable());
// t.start();
exe.execute(new MyRunnable());
}
//如果不结束,将会一直运行,虽然没有线程了。
exe.shutdown();
}
}
实现多线程主要有两种方式,一种是实现Runnable接口,一种是直接继承Thread类,两种方式大同小异。实现多线程也可以实现匿名类的方式来实现。上面的例子使用了Runnable接口来实现一个多线程的并发,启动线程有两种那个方式,一种是Tread.start(),一种是使用线程池类似,来调用执行。使用线程池可以更好的管理线程,常见的线程池类型有CacheThreadPool,FixThreadPool,和SingleThreadPool.下面我们来看看FixedThreadPool和SingleThreadPool的执行的例子,我们分别写一个main函数,来执行上面的过程,如下所示:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FixedThreadPool {
public static void main(String[] args){
//FixedThreadPool,设置线程池容量为5
ExecutorService exe = Executors.newFixedThreadPool(5);
for(int i=0;i<10;i++){
exe.execute(new MyRunnable());
}
}
}
上述没有使用exe.shutdown()方法,我们来看看结果,运行结果如下:
可以看到,每次同时运行的线程只有5个,一开始运行的线程只有0,1,2,3,4,,o退出之后,5开始运行,1退出之后,6开始运行,这就是FixedThreadPool。同时你应该注意到,程序没有结束,但是也不再打印新的东西了。
下面我们来看看SingleThreadPool的用法
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SingleThreadPool {
public static void main(String[] args) {
// TODO Auto-generated method stub
ExecutorService exe = Executors.newSingleThreadExecutor();
for(int i=0;i<5;i++){
exe.execute(new MyRunnable());
}
exe.shutdown();
}
}
运行结果如下
可以看到无路如何,这些线程都是并行运行的。
有的时候你需要从你的线程返回你需要的值,你如果用Thread来实现,那是比较困难的。但是你可以用下面这种办法啊。
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class TaskWithResult implements Callable<Integer>{
int begin;
int end;
public TaskWithResult(){
}
public TaskWithResult(int begin,int end){
this.begin=begin;
this.end=end;
}
@Override
public Integer call() throws Exception {
int total=0;
for(int i=begin;i<end;i++){
total+=i;
}
return total;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ExecutorService exe = Executors.newCachedThreadPool();
ArrayList<Future<Integer>> futureList = new ArrayList<Future<Integer>>();
for(int i=0;i<100000;i+=10000){
futureList.add(exe.submit(new TaskWithResult(i,i+10000)));
}
exe.shutdown();
int total=0;
for(Future f:futureList){
try {
Integer i = (Integer) f.get();
total+=i;
} catch (InterruptedException | ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(total);
int total2=0;
for(int i=0;i<100000;i++){
total2+=i;
}
System.out.println(total2);
}
}
具体的不多说,主要的思路就是实现了从0加到十万。第一种办法是使用了多线程的做法,分了是个线程,第二种做法是采用了直接加的做法。当然,也不一定谁好谁坏,这个要看虚拟机的支持了。
休眠/让步/优先级/后台线程和ThreadFactory
--sleep,以及TimeUnit类,可以自己参考jdk文档;TimeUnit.[interval].sleep([length】)
--new Thread().yield()方法;
--new Thread(new Runnable()).setPriority(int) 以及new Thread(new Runnable).getPriority();Java一般有10级,分别从1-10;
--重点来说一下后台线程,后台线程也是有Thread的实例对象来调用的,只要你在使用start方法之前调用了setDaemon()方法,那么你就能够将线程变为后台线程。后台线程有一个特性,那就是当前台线程全部结束的时候,不管后台线程有没有结束,它都要全部结束,我们来看个后台线程和ThradFactory结合的例子
import java.util.concurrent.*;
public class MyThreadFactory implements ThreadFactory{
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
//将所有的线程都设置为后台线程
t.setDaemon(true);
return t;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ExecutorService exe = Executors.newCachedThreadPool(new MyThreadFactory());
for(int i=0;i<5;i++){
exe.execute(new Mydaemon());
}
exe.shutdown();
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class Mydaemon implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<5;i++){
try {
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread()+" "+this);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
加入一个线程,join的应用
一个线程可以在其他线程之上调用join()方法,其效果是等待一段时间直到第二个线程结束才继续执行。如果某个线程在另一个线程t上调用t.join(),此线程将被挂起,直到目标线程结束才恢复。也可以加上一个超时参数,这样如果目标线程在这段时间内到期时还没有结束的话,join方法总是能反回,防止长时间等待。如下所示:
public class Sleeper extends Thread{
public int duration;
public Sleeper(String name, int sleepTime){
super(name);
this.duration = sleepTime;
start();
}
public void run(){
try{
sleep(duration);
}catch(InterruptedException e){
// e.printStackTrace();
System.out.println(getName()+" is interrupt");
return;
}
System.out.println(getName()+" has awakened");
}
public static void main(String[] args){
Sleeper
sleeper1 = new Sleeper("sleeper1", 1500),
sleeper2 = new Sleeper("sleeper2", 1500);
Joiner
Joiner1 = new Joiner("Joiner1", sleeper1),
Joiner2 = new Joiner("joiner2", sleeper2);
sleeper2.interrupt();
}
}
class Joiner extends Thread{
private Sleeper sleeper;
public Joiner(String name,Sleeper sleeper){
super(name);
this.sleeper=sleeper;
start();
}
public void run(){
try{
sleeper.join();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(getName()+" join completed");
}
}