线程池

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

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

使用线程池方式--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. 性能测试工具Jmeter06-Jmeter元件作用域和执行顺序

    元件作用域 8类可被执行的元件(测试计划与线程组不属于可执行元件),这些元件中,取样器(sampler)是典型的不与其它元件发生交互作用的元件,逻辑控制器只对其子节点的取样器有效,而其它元件(配置元件 ...

  2. express中connect-flash中间件的使用

    在学习node的时候,flash是困扰我最久的一个中间件,之前一直都没有很好的理解,这里做一个总结. 参考自:http://yunkus.com/connect-flash-usage/ 什么是fla ...

  3. 断路器hystrix

    分布式系统中不可避免的会出现一些故障,因为服务间错综复杂的依赖关系,有时候一个服务出现问题后,会导致依赖于它的服务出现远程调度的线程受阻,给服务造成压力,当然同样的,祖父级调用者(暂且这么叫吧)当然也 ...

  4. Python 科学工具笔记

    Python 科学工具笔记 numpy a = numpy.array([1,2,3,4]);// 创建一个numpy的数组对象 此时a.shape显示的值为(4,); 由此得出结论在一维的数组中, ...

  5. JVM:java类的加载机制

    原文连接:https://www.cnblogs.com/ityouknow/p/5603287.html 类加载机制的奥妙. 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读 ...

  6. C++中的虚函数表

    (感谢http://blog.csdn.net/haoel/article/details/1948051/) C++中的虚函数的作用主要是实现了多态的机制. 多态,简而言之就是用父类型别的指针指向其 ...

  7. 收藏 创建第一个mvc

    http://blog.csdn.net/sdtsfhh/article/details/8201956

  8. CSS命名规范(规则)

    常用的CSS命名规则 头:header内容:content/container尾:footer导航:nav侧栏:sidebar栏目:column页面外围控制整体佈局宽度:wrapper左右中:left ...

  9. LotusScript_批量更改数据库标识符(id)

    OA开发中经常要搭建测试环境,测试环境的数据库与原数据库不能有ID冲突现象,以防混淆.以下是一个批量修改数据库标识符的方法,其中,取得这些需要更改的数据库,需要导出源服务器上的数据库路径和名称,方法详 ...

  10. Android 设置软键盘搜索键以及监听搜索键点击事件

    如图所示,有时候为了布局美观,在搜索时没有搜索按钮,而是调用软件盘上的按钮.调用的实现只需要在XML在输入框中加入android:imeOptions="actionSearch" ...