线程池

  线程池,其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。

除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。线程池主要用来解决线程生命周期开销问题和资源不足问题。

使用线程池方式--Runnable接口

通常,线程池都是通过线程池工厂创建,再调用线程池中的方法获取线程,再通过线程去执行任务方法。

Executors:线程池创建工厂类
public static ExecutorService newFixedThreadPool(int nThreads):返回线程池对象
ExecutorService:线程池类
Future<?> submit(Runnable task):获取线程池中的某一个线程对象,并执行
Future接口:用来记录线程任务执行完毕后产生的结果。线程池创建与使用

使用线程池中线程对象的步骤:

1.  创建线程池对象

2.  创建Runnable接口子类对象

3.  提交Runnable接口子类对象

4.  关闭线程池

package com.oracle.xiancheng;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class Xiancheng {
public static void main(String[] args) {
//创建线程池对象(从线程池工厂中获得)
ExecutorService ec=Executors.newFixedThreadPool(2);
//创建Runnable接口子类实例对象(创建任务对象)
MyRunnable r = new MyRunnable();
// 提交Runnable接口子类对象
//线程池会选一条线程执行提交的任务
ec.submit(r);
//注意:submit方法调用结束后,程序并不终止,是因为线程池控制了线程的关闭。
//又将使用完的线程又归还到了线程池中
for(int i=0;i<50;i++){
System.out.println("main..."+i);
}
ec.shutdown();//关闭线程池
}
}

Runnable接口实现类

package com.oracle.xiancheng;
public class MyRunnable implements Runnable { public void run() {
for(int i=0;i<50;i++){
System.out.println("runable..."+i);
}
}
}

使用线程池方式—Callable接口

Callable接口:与Runnable接口功能相似,用来指定线程的任务。其中的call()方法,用来返回线程任务执行完毕后的结果,call方法可抛出异常。
ExecutorService:线程池类
<T> Future<T> submit(Callable<T> task):获取线程池中的某一个线程对象,并执行线程中的call()方法
Future接口:用来记录线程任务执行完毕后产生的结果。线程池创建与使用

  使用线程池中线程对象的步骤:

  1. 创建线程池对象

  2. 创建Callable接口子类对象

  3. 提交Callable接口子类对象

  4.  关闭线程池

Callable接口实现类,call方法可抛出异常、返回线程任务执行完毕后的结果

package com.oracle.xiancheng;

import java.util.concurrent.Callable;

//Callable泛型就是你call的返回值类型
public class MyCallable implements Callable<String> {
public String call() throws Exception { return "这是call方法";
} }

测试类:

package com.oracle.xiancheng;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; public class demo01 { public static void main(String[] args) throws InterruptedException, ExecutionException {
//获取线程池
ExecutorService ec=Executors.newFixedThreadPool(2);
//创建callable子类
MyCallable mc=new MyCallable();
//提交Callable子类
Future<String> f=ec.submit(mc);
String str=f.get();
System.out.println(str);
//关闭线程池
ec.shutdown();
} }

异步计算0-100的和跟0-200的和

package com.oracle.xiancheng;

import java.util.concurrent.Callable;

public class JiSuan  implements Callable<Integer>{
private Integer a;
public JiSuan(Integer a){
this.a=a;
}
public Integer call(){
int sum=0;
for(int i=0;i<=a;i++){
sum +=i;
}
System.out.println(sum);
return sum;
} }

测试类:

package com.oracle.xiancheng;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; public class Yibu {
//异步计算0-100的和跟0-200的和
public static void main(String[] args) throws InterruptedException, ExecutionException {
//获取线程池 ExecutorService ec=Executors.newFixedThreadPool(2);
//创建callable子类
JiSuan js=new JiSuan(100);
JiSuan js1=new JiSuan(200);
//提交callable子类
Future<Integer> f1=ec.submit(js);
Future<Integer> f2=ec.submit(js1);
/*//从future中获取返回值
System.out.println(f1.get());
System.out.println(f2.get());*/
//关闭
ec.shutdown();
} }

多线程

线程安全

  电影院要卖票,我们模拟电影院的卖票过程。假设要播放的电影是 “功夫熊猫3”,本次电影的座位共100个(本场电影只能卖100张票)。

我们来模拟电影院的售票窗口,实现多个窗口同时卖 “功夫熊猫3”这场电影票(多个窗口一起卖这100张票)

需要窗口,采用线程对象来模拟;需要票,Runnable接口子类来模拟

模拟票:

public class Ticket implements Runnable {
private int tickets=100;
public void run(){
    //模拟卖票
while(true){ if(tickets>0){
          //模拟选座
try {
Thread.sleep(10);
} catch (InterruptedException e) { e.printStackTrace();
} System.out.println(Thread.currentThread().getName()+"出售第"+tickets--+"张票");
} }
}
}

测试类;

package com.oracle.demo01;

public class demo01 {
public static void main(String[] args) {
Ticket t=new Ticket();//创建票对象
Thread t1=new Thread(t);
Thread t2=new Thread(t);
Thread t3=new Thread(t);
t1.start();
t2.start();
t3.start(); }
}

结果会出现重复的票,还有错误的票,0和-1问题

线程同步(线程安全处理Synchronized)

java中提供了线程同步机制,它能够解决上述的线程安全问题。

线程同步的方式有两种:

方式1:同步代码块

方式2:同步方法

同步代码块

//同步代码块: 在代码块声明上 加上synchronized
synchronized (锁对象) {
//可能会产生线程安全问题的代码
}

  同步代码块中的锁对象可以是任意的对象;但多个线程时,要使用同一个锁对象才能够保证线程安全。

使用同步代码块,对电影院卖票案例中Ticket类进行如下代码修改:

模拟出票

public class Ticket implements Runnable {
private int tickets=100;
private Object lock = new Object();
public void run(){
while(true){ synchronized (lock) {
if(tickets>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} System.out.println(Thread.currentThread().getName()+"出售第"+tickets--+"张票");
}else{
break;
}
} }
}

同步方法

//同步方法:在方法声明上加上synchronized
public synchronized void method(){
//可能会产生线程安全问题的代码
}

同步方法中的锁对象是 this

使用同步方法,对电影院卖票案例中Ticket类进行如下代码修改:

package com.oracle.demo01;

public class Ticket implements Runnable {
private int tickets=100;
private Object lock = new Object(); public void run() {
//模拟卖票
while(true){
//同步方法
method();
}
} //同步方法,锁对象this
public synchronized void method(){
if (tickets> 0) {
//模拟选坐的操作
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"出售第"+tickets--+"张票");
}
} }
//静态同步方法: 在方法声明上加上static synchronized
public static synchronized void method(){
//可能会产生线程安全问题的代码
}

 静态同步方法中的锁对象是本类字节码对象  类名.class

同步锁:对象锁,对象监视器

同步是怎么保证安全性?

 因为同步中有锁,没有锁的线程,不能执行,只能等。

StringBuilder比StringBuffer快

原因:StringBuffer有同步关键字synchronized,安全性比StringBuilder高,但速度慢

死锁

  同步锁使用的弊端:当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步。这时容易引发一种现象:程序出现无限等待,这种现象我们称为死锁。

格式如:

synchronzied(A锁){
synchronized(B锁){   }
}

定义锁对象类:

package com.oracle.demo01;

public class LockA {
public final static LockA locka=new LockA();
private LockA(){ }
}
package com.oracle.demo01;

public class LockB {
public final static LockB lockb=new LockB();
private LockB(){ }
}

线程任务类:

package com.oracle.demo01;

public class DeadLock implements Runnable {
private int i=0; public void run() { while(true){
if(i%2==0){
//情况一
synchronized (LockA.locka){
System.out.println("IF......lockA");
synchronized (LockB.lockb){
System.out.println("IF......lockB");
}
}
}else{
//情况二
synchronized (LockB.lockb){
System.out.println("else......lockB");
synchronized (LockA.locka){
System.out.println("else......lockA");
}
}
}
i++;
}
} }

测试类:

package com.oracle.demo01;

public class TestDEADlock {

    public static void main(String[] args) {
//创建线程任务类对象
DeadLock dl=new DeadLock();
//创建两个线程
Thread t1=new Thread(dl);
Thread t2=new Thread(dl);
//开启线程
t1.start();
t2.start(); } }

Lock接口

  使用Lock接口,以及其中的lock()方法和unlock()方法替代同步,对电影院卖票案例中Ticket类进行如下代码修改:

package com.oracle.demo01;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class NewTicket implements Runnable{
private int tickets=100;
//创建Lock锁对象
private Lock ck = new ReentrantLock();
public void run(){
while(true){
ck.lock();
if(tickets>0){
try {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName()+"出售第"+tickets--+"张票"); } catch (InterruptedException e) { e.printStackTrace();
}finally{
ck.unlock();//释放锁
} }
}
} }

线程池,多线程,线程异步,同步和死锁,Lock接口的更多相关文章

  1. -1-5 java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait(),notify(),notifyAll()等方法都定义在Object类中

     本文关键词: java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁  sleep()和wait()方法的区别 为什么wait( ...

  2. Java多线程、线程池和线程安全整理

    多线程 1.1      多线程介绍 进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 1.2      Thread类 通 ...

  3. 异步线程编程,线程池,线程组,后面涉及ThreadLocal在理解

    join模拟订单 package com.future.demo.future; /** * * * @author Administrator * */ public class NormalThr ...

  4. Spring使用ThreadPoolTaskExecutor自定义线程池及实现异步调用

    多线程一直是工作或面试过程中的高频知识点,今天给大家分享一下使用 ThreadPoolTaskExecutor 来自定义线程池和实现异步调用多线程. 一.ThreadPoolTaskExecutor ...

  5. 多线程、线程池、线程创建、Thread

    转载自https://www.cnblogs.com/jmsjh/p/7762034.html 多线程 1.1 多线程介绍 学习多线程之前,我们先要了解几个关于多线程有关的概念. 进程:进程指正在运行 ...

  6. Java多线程系列 JUC线程池07 线程池原理解析(六)

     关闭“线程池” shutdown()的源码如下: public void shutdown() { final ReentrantLock mainLock = this.mainLock; // ...

  7. Java多线程系列 JUC线程池03 线程池原理解析(二)

    转载  http://www.cnblogs.com/skywang12345/p/3509954.html  http://www.cnblogs.com/skywang12345/p/351294 ...

  8. Java多线程系列 JUC线程池02 线程池原理解析(一)

    转载  http://www.cnblogs.com/skywang12345/p/3509960.html ; http://www.cnblogs.com/skywang12345/p/35099 ...

  9. Java多线程系列 JUC线程池01 线程池框架

    转载  http://www.cnblogs.com/skywang12345/p/3509903.html 为什么引入Executor线程池框架 new Thread()的缺点 1. 每次new T ...

  10. 由浅入深理解Java线程池及线程池的如何使用

    前言 多线程的异步执行方式,虽然能够最大限度发挥多核计算机的计算能力,但是如果不加控制,反而会对系统造成负担.线程本身也要占用内存空间,大量的线程会占用内存资源并且可能会导致Out of Memory ...

随机推荐

  1. 解决ajax提交中文数据乱码

    function replaceWord(date,wordurl){                $.ajax({            url : 'wordReplace',          ...

  2. IntelliJ IDEA里找不到javax.servlet的jar包

    此处有小坑,请注意: https://mvnrepository.com网站查询到的servlet的包的格式为: provided group: 'javax.servlet', name: 'jav ...

  3. apache服务器启动出错

    启动本地xampp的服务器时,报错如下所示: 错误提示很明确: 就是指我们希望使用的端口被占用,由于xampp默认使用的端口是80(http协议).443(https协议),也就是说这两个端口被其他的 ...

  4. ApplicationContextAware的作用

    ApplicationContextAware其实我们看到---Aware就知道是干嘛用的了,就是属性注入的, 但是这个ApplicationContextAware的不同地方在于,实现了这个接口的b ...

  5. iOS 状态栏设置为白色

    1.首先需要再info.plist中添加一项View controller-based status bar appearance为no 2.在需要的地方添加代码 [[UIApplication sh ...

  6. The fourteenth day

    A man is not old as long as he is seeking something. A man is not old until regrets take the place o ...

  7. 使用Ribbon Workbench来修改停用、激活按钮的权限

    在实施的过程中,有时会遇到客户为了管控使用人员的操作或防止使用人员通过停用后再激活来绕开部分逻辑,需要对激活.停用按钮赋予单独的权限.但很遗憾,在Dyanmics CRM中,并没有把停用.激活按钮单独 ...

  8. 在Git上创建新分支(实用性高!!!)

    在github上创建仓库: Create a new repository on the command line touch README.md git init git add README.md ...

  9. Visual Studio Code 入门教程

    Extensible and customizable.(可扩展的和可定制的,这是我喜欢它的原因) Want even more features? Install extensions to add ...

  10. selenium并行的使用

    Selenium Grid Parallel Test(C#) Author: Mars (hnynes)Email:  hnynes@gmail.comMSN:    hnynes@gmail.co ...