标签:
并发编程可以帮助我们将程序划分为多个分离的、独立运行的任务。通过多线程机制,这些独立任务中的每一个都将由执行线程来驱动。一个线程就是在进程中的一个单一的顺序控制流,因此单个进程可以拥有多个并发执行的任务,但是程序使得每个任务都好像拥有自己的CPU一样,其底层机制是切分CPU时间。CPU会轮流为每个任务分配占用时间。
每个线程拥有各自独立的地址空间,而其中的静态成员变量是可以被多个线程共享的,例如下面程序中的i,i的地址是唯一的,并且永远存放在静态区域,因此,每次对i进行加载读取写入都是有可能发生不正当竞争的,为了保证读写安全,特别对i进行加锁synchronized,这样保证了安全读写。
package concurrency; /** * 并发问题,多线程的静态变量可以共享i * @author zzw922cn * */ public class CountRunnable implements Runnable { private static Integer i=0; @Override public void run() { synchronized(i) { System.out.println(Thread.currentThread().getName()+":"+(++i)); } } }
package concurrency; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Test1 { public static void main(String[] args) { //Executors.newCachedThreadPool()用来新建线程池,如果有空闲线程就使用它,否则就新建新线程 ExecutorService newCachedThreadPool = Executors.newCachedThreadPool(); Thread[] thread = new Thread[10]; for(int i=0;i<thread.length;i++) { thread[i]=new Thread(new CountRunnable()); newCachedThreadPool.submit(thread[i]); } newCachedThreadPool.shutdown(); } }
pool-1-thread-2:2 pool-1-thread-4:4 pool-1-thread-3:3 pool-1-thread-1:1 pool-1-thread-5:5 pool-1-thread-6:6 pool-1-thread-7:7 pool-1-thread-8:8 pool-1-thread-10:9 pool-1-thread-9:10
有时候,我们在分割任务时,同时还希望每个任务执行完毕能够返回一些数据给主进程,这时候我们可以使用实现Callable接口的方式来实现。Callable是个泛型接口,其中必须要实现的方法是Call()方法,该方法的返回值即该任务向主线程提交的返回值,由于是泛型的,因此我们可以返回任意类型的对象。
下面,我们来进行多个求和任务的分割,代码如下:
package concurrency; import java.util.concurrent.Callable; public class CountNumberTask implements Callable<Integer> { private int num; /** * 构造函数 * @param num 末尾数 */ public CountNumberTask(int num) { this.num = num; } /** * 实现call函数,返回结果 */ @Override public Integer call() throws Exception { int sum=0; for(int i=1;i<=num;i++) { sum+=i; } return sum; } }
package concurrency; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * 耗时26秒 * @author zzw922cn * */ public class CountNumberTest { public static void main(String[] args) { long t1 = System.currentTimeMillis(); ExecutorService newCachedThreadPool = Executors.newFixedThreadPool(2); for(int i=1;i<=300000;i++) { Future<Integer> submit = newCachedThreadPool.submit(new CountNumberTask(i)); try { Integer integer = submit.get(); System.out.println(integer); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } newCachedThreadPool.shutdown(); long t2 = System.currentTimeMillis(); System.out.println("多线程耗时"+(t2-t1)/1000.0+"s"); } }
package concurrency; /** * 耗时37秒 * @author zzw922cn * */ public class CountNumberTest2 { public static void main(String[] args) { long t1 = System.currentTimeMillis(); for(int i=1;i<=300000;i++) { int sum=0; for(int j=0;j<=i;j++) { sum+=j; } System.out.println(sum); } long t2 = System.currentTimeMillis(); System.out.println("单线程耗时"+(t2-t1)/1000.0+"s"); } }
所谓守护线程(又称作后台线程),是指在程序运行的时候在后台提供一种通用服务的线程,并且这种线程并不属于程序中不可或缺的一部分。当所有非守护进程结束时,程序就终止了,同时也会杀死程序的所有守护线程,守护线程在被杀死时,不会执行finally语句块。
package concurrency; public class DeamonRunnable implements Runnable { @Override public void run() { try { while(true) { Thread.sleep(100); System.out.println(Thread.currentThread()+" "+this); } } catch(InterruptedException ex) { System.out.println("Sleep() interrupted!"); } } }
package concurrency; import java.util.concurrent.TimeUnit; public class DeamonRunnableTest { public static void main(String[] args) throws InterruptedException { for(int i=0;i<10;i++) { Thread thread = new Thread(new DeamonRunnable()); thread.setDaemon(true); thread.start(); } //设置主线程休眠,所以能看到守护线程 TimeUnit.MILLISECONDS.sleep(175); } }
Thread[Thread-1,5,main] concurrency.DeamonRunnable@4908d73b Thread[Thread-6,5,main] concurrency.DeamonRunnable@3f91c80b Thread[Thread-5,5,main] concurrency.DeamonRunnable@1fb44aeb Thread[Thread-0,5,main] concurrency.DeamonRunnable@12d4f26 Thread[Thread-2,5,main] concurrency.DeamonRunnable@210c4256 Thread[Thread-4,5,main] concurrency.DeamonRunnable@65c16078 Thread[Thread-3,5,main] concurrency.DeamonRunnable@7dca373f Thread[Thread-9,5,main] concurrency.DeamonRunnable@7105d5e Thread[Thread-8,5,main] concurrency.DeamonRunnable@7995373b Thread[Thread-7,5,main] concurrency.DeamonRunnable@6bad1bc1
通过下面的代码运行结果我们会发现,对于守护线程而言,它的所有子线程也都是守护线程。
package concurrency; public class Daemon implements Runnable { private Thread[] t=new Thread[10]; @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<t.length;i++) { t[i]=new Thread(new DaemonSpawn()); t[i].start(); System.out.println(t[i]+"has started!"); } for(int i=0;i<t.length;i++) { System.out.println(t[i]+"is DaemonThread:"+t[i].isDaemon()); } while(true) { Thread.yield(); } } }
package concurrency; public class DaemonSpawn implements Runnable { @Override public void run() { while(true) { //让步 Thread.yield(); } } }
package concurrency; public class DaemonTest { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Daemon()); thread.setDaemon(true); thread.start(); System.out.println(thread+"isDaemonThread:"+thread.isDaemon()); Thread.sleep(100); } }
Thread[Thread-0,5,main]isDaemonThread:true Thread[Thread-1,5,main]has started! Thread[Thread-2,5,main]has started! Thread[Thread-3,5,main]has started! Thread[Thread-4,5,main]has started! Thread[Thread-5,5,main]has started! Thread[Thread-6,5,main]has started! Thread[Thread-7,5,main]has started! Thread[Thread-8,5,main]has started! Thread[Thread-9,5,main]has started! Thread[Thread-10,5,main]has started! Thread[Thread-1,5,main]is DaemonThread:true Thread[Thread-2,5,main]is DaemonThread:true Thread[Thread-3,5,main]is DaemonThread:true Thread[Thread-4,5,main]is DaemonThread:true Thread[Thread-5,5,main]is DaemonThread:true Thread[Thread-6,5,main]is DaemonThread:true Thread[Thread-7,5,main]is DaemonThread:true Thread[Thread-8,5,main]is DaemonThread:true Thread[Thread-9,5,main]is DaemonThread:true Thread[Thread-10,5,main]is DaemonThread:true
标签:
原文地址:http://my.oschina.net/zzw922cn/blog/494168