Java 并发基础
来源:互联网 发布:zigbee协议栈编程 编辑:程序博客网 时间:2024/06/16 12:21
Java 并发
基本线程
1、定义任务
实现Runnable接口并编写run()方法
class PrimeRun implements Runnable { long minPrime; PrimeRun(long minPrime) { this.minPrime = minPrime; } //实现run方法 public void run() { } }
继承Thread类
class PrimeThread extends Thread { long minPrime; PrimeThread(long minPrime) { this.minPrime = minPrime; } //重写Thread类的run方法 public void run() { . . . } }
2、使用Executor
在JDK5中,在java.util.concurrent包中引入了Executors线程池,使得创建多线程更加方便高效
public class CachedThreadPool{ public static void main(String[] args){ //创建一个缓冲线程池服务 ExecutorService exec = Executors.newCachedThreadPool(); for(int i=0; i<5; i++){ //线程池服务启动线程 exec.execute(new PrimeRun()); } //线程池服务停止 exec.shoutdown(); } }
- Executors.newCachedThreadPool()在程序执行过程中通常会创建与所需数量相同的线程,然后在它回收旧线程时停止创建新线程,因此它是首选
- Executors.newFixedThreadPool(intsize)方法创建固定数目的线程池,即程序会创建指定数量的线程,每次同时运行intsize个线程
- Executors.newSingleThreadPool()创建单线程池,即固定数目为1的线程池相当于(Executors.newFixedThreadPool(1))
3、任务返回值
Runnable是执行工作的独立的任务,但它不好返回任何值,在Java SE5中引入的Callabel是一个具有类型参数的泛型,从方法call()(不是run())中返回的值
import java.util.concurrent.*; import java.util.*; class TaskWithResult implements Callable<String>{ private int id; public TaskWithResult(int id){ this.id = id; } public String call(){ return “result of TaskWithResult ” + id; } public static void main(String[] args){ ExecutorService exec = Executors.newCachedThreadPool(); List<Future<String>> results = new ArrayList<Future<String>>(); for(int i=0; i<5; i++){ //将线程返回值添加到List中 results.add(exec.submit(new TaskWithResult(i))); } //遍历获取线程返回值 for(Future<String> fs : results){ try{ System.out.println(fs.get()); }catch(Exception e){ System.out.println(e); }finally{ exec.shutdown(); } } } }
输出结果(可能的结果,由于多线程执行顺序不确定,结果不固定):
result of TaskWithResult 0
result of TaskWithResult 1
result of TaskWithResult 3
result of TaskWithResult 4
result of TaskWithResult 5
注解:使用线程池服务的submit()方法执行线程池时,会产生Future对象,其参数类型是线程Callable的call()方法返回值的类型,使用Future对象的get()方法可以获取线程返回值。
休眠
简单的方法使用sleep(),使任务中止执行给定的时间
注意:不论是Thread.sleep还是TimeUnit的sleep线程休眠方法,都要捕获InterruptedExecutors。
4、优先级
线程的优先级将该线程的重要性传递给了调度器,CPU处理现有线程集的顺序使不确定的,但是调度器将倾向于让优先级最高的线程先执行。
可以通过Thread线程对象的getPriority()方法获取线程的优先级,可以通过线程对象的setPriority()方法设置线程的优先级。
Java的线程优先级总共有10级,最低优先级为1,最高为10,Windows的线程优先级总共有7级并且不固定,而Sun的Soloaris操作系统有23级,因此java的线程优先级无法很好地和操作系统线程优先级映射,所有一般只使用MAX_PRIORITY(10),NORM_PRIORITY(5)和MIN_PRIORITY(1)这三个线程优先级。
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 Thrad.currentThread()+":"+countDown; } public void run(){ Thread.currentThread().setPriority(priority); while(true){ for(int i=0;i<100000;i++){ d+=(Math.PI+Math.E) if(i%1000==0){ Thread.yield(); } } } System.out.println(this); if(--countDown==0) return; }}
5、守护(daemon)线程
守护线程(DaemonThread)是某些提供通用服务的在后台运行的程序,是优先级最低的线程。当所有的非守护线程执行结束后,程序会结束所有的守护线程而终止运行。如果当前还有非守护线程的线程在运行,则程序不会终止,而是等待其执行完成。
public class SimpleDaemons implements Runnable{ public void run{ try{ System.out.println(“Start daemons”); TimeUtil.SECONDS.sleep(1); }catch(Exception e){ System.out.println(“sleep() interrupted”); }finally{ System.out.println(“Finally is running”); } } public static void main(String[] args) throws Exception{ Thread daemon = new Thread(new SimpleDaemons()); daemon.setDaemon(true); daemon.start(); } }
输出结果:
Start daemons
Finally没有执行,如果注释掉daemon.setDaemon(true)设置守护进程这一句代码。
输出结果:
Start daemons
Finally is running
之所以产生这样的结果原因是,main()是这个程序中唯一的非守护线程,当没有非守护线程在运行时,JVM强制推出终止守护线程的运行。
通过Thread对象的setDaemon方法可以设置线程是否为守护线程,通过isDaemon方法可以判断线程对象是否为守护线程。
由守护线程创建的线程对象不论有没有通过setDaemon方法显式设置,都是守护线程。
6、synchronized
编程中的共享资源问题会引起多线程的竞争,为了确保同一时刻只有一个线程独占共享资源,需要使用线程同步机制,即使用前对共享资源加锁,使用完毕之后释放锁。
Java中通过synchronized关键字实现多线程的同步,线程同步可以分为以下几种:
1、对象方法同步:
public synchronized void methodA(){ System.out.println(this); }
2、类所有对象方法同步:
public synchronized static void methodB(){ System.out.println(this); }
静态方法的线程同步锁对类的所有对象都起作用,即所有对象的线程在同一时刻只能有一个类的一个线程调用该方法。
3、对象同步代码块
public void methodC(){ synchronized(this){ System.out.println(this); } }
使用当前对象作为线程同步锁,同一个对象的不同线程在同一时刻只能有一个线程调用methodC方法中的代码块。
4、类同步代码块:
public void methodD(){ synchronized(className.class){ System.out.println(this); } }
使用类字节码对象作为线程同步锁,类所有对象的所有线程在同一时刻只能有一个类的一个线程调用methodD的同步代码块。
注意:线程的同步是针对对象的,不论是同步方法还是同步代码块,都锁定的是对象,而非方法或代码块本身。每个对象只能有一个线程同步锁与之关联。
7、捕获异常
线程产生的异常会传播到run()方法的外部,并且main()展示,但将放入try-catch语句块中是没有作用的还会是未捕获异常
public class ExceptionThread implements Runnable { @Override public void run() { throw new RuntimeException("这个线程就干了这么一件事,抛出一个运行时异常"); } public static void main(String[] args) { try { ExecutorService exec = Executors.newCachedThreadPool(); exec.execute(new ExceptionThread()); System.out.println("该干嘛干嘛去"); } catch (RuntimeException e) { System.out.println("能不能捕获到异常?"); } }}
运行结果
该干嘛干嘛去Exception in thread "pool-1-thread-1" java.lang.RuntimeException: 这个线程就干了这么一件事,抛出一个运行时异常 at ExceptionThread.run(ExceptionThread.java:8) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:619)
Thread.UncaughtExceptionHandlersh是Java SE5的新接口,运行你在每个Thread对象上都附着一个异常处理器
public class MyUnchecckedExceptionhandler implements UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("捕获到异常:" + e); }}
main()
public class HandlerThreadFactory implements ThreadFactory { @Override public Thread newThread(Runnable r) { System.out.println("创建一个新的线程"); Thread t = new Thread(r); t.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler()); System.out.println("eh121 = " + t.getUncaughtExceptionHandler()); return t; }}
如果想让每个线程都默认异常处理器那么需要添加以下代码
Thread.setDefaultUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
这将产生和上面一样的结果
public class HandlerThreadFactory implements ThreadFactory { @Override public Thread newThread(Runnable r) { System.out.println("创建一个新的线程"); Thread.setDefaultUncaughtExceptionHandler(new MyUnchecckedExceptionhandler()); Thread t = new Thread(r); System.out.println("eh121 = " + t.getUncaughtExceptionHandler()); return t; }}
8、显式锁lock
JDK5之后,在java.util.concurrent.locks包中引入了显式锁机制
Lock对象必须显示的创建、锁定、释放
public class Locking{ //创建锁 private ReentrantLock lock = new ReentrantLock(); public void untimed(){ boolean captured = lock.tryLock(); try{ System.out.println(“tryLock(): ” + captured); }finally{ if(captured){ lock.unlock(); } } }
- Java并发基础
- Java基础&增强 并发
- 【Java基础】并发 - 多线程
- Java并发编程基础
- Java并发编程基础
- java并发基础总结
- java并发基础
- java并发基础--线程
- Java 并发基础
- Java线程并发基础
- java多线程并发基础
- Java并发编程基础
- Java并发基础
- Java 并发编程 基础
- Java并发基础总结
- Java并发基础
- Java并发基础
- Java并发 基础 二
- hdu 6143 Killer Names (2017多校第八场)
- 利用多线程和信号量,互斥量实现的经典的生产者与消费者模型
- 二分法查找
- android__shape 圆角矩形 圆环画法
- 单链表逆转、字符串按单词逆转
- Java 并发基础
- 实现一个clone函数并可以对js中的5种主要数据类型进行值复制
- 线段树基础与模板与简单应用
- Cow Acrobats
- qt+ffmpeg仿格式工厂
- 借助AMD来解决HTML5游戏开发中的痛点
- RxJava2总结之操作详解(三)
- leetcod
- wchar_t 和 char16_t, char32_t的使用方法 ——C++