java_线程、同步、线程池
线程
Java使用 java.lang.Thread 类代表线程,所有的线程对象都必须是Thread类或其子类的实例
Thread类常用方法
构造方法
public Thread():分配一个新的线程对象。
public Thread(String name):分配一个指定名字的新的线程对象。
public Thread(Runnable target):分配一个带有指定目标新的线程对象。
public Thread(Runnable target,String name):分配一个带有指定目标新的线程对象并指定名字。
常用方法
public string getName():获取当前线程名称。
public void start():导致此线程开始执行;Java虚拟机调用此线程的run方法。
public void run():此线程要执行的任务在此处定义代码。
public static void sleep(long millis):使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
public static Thread currentThread():返回对当前正在执行的线程对象的引用。
创建线程方式一
Java中通过继承Thread类来创建并启动多线程的步骤如下:
定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把 run()方法称为线程执行体。
创建Thread子类的实例,即创建了线程对象
调用线程对象的start()方法来启动该线程
测试类:
public class Demo{
public static void main(String[] args) {
// 创建自定义线程对象
MyThread mt = new MyThread("新线程");
// 开启新线程
mt.start();
// 在主方法中执行for循环
for (int i = 0; i < 10; i++) {
System.out.println("main线程正在执行" + i);
}
}
}
自定义线程类:
public class MyThread extends Thread {
// 定义指定线程名称的构造方法
public MyThread(String name) {
// 调用父类的String参数的构造方法,指定线程的名称
super(name);
}
/**
* 重写run方法,完成该线程执行的逻辑
*/
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName() + "正在执行" + i);
}
}
}
流程图:
程序启动运行main时候,java虚拟机启动一个进程,主线程main在main()调用时候被创建。
随着调用mt的对象的start方法,另外一个新的线程也启动了,这样,整个应用就在多线程下运行。
创建线程方式二
Java中通过实现Runnable接口来创建并启动多线程的步骤如下:
定义Runnable接口的实现类,并重写该接口的run () 方法,该run () 方法的方法体同样是该线程的线程执行体。
创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
调用线程对象的start () 方法来启动线程。
测试类:
public class Demo {
public static void main(String[] args) {
// 创建自定义类对象线程任务对象
MyRunnable mr = new MyRunnable();
// 创建线程对象
Thread t = new Thread(mr, "新线程");
t.start();
for (int i = 0; i < 10; i++) {
System.out.println("main线程正在执行" + i);
}
}
}
自定义线程类:
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "正在执行" + i);
}
}
}
通过实现Runnable接口,使得该类有了多线程类的特征。run () 方法是多线程程序的一个执行目标。所有的多线程代码都在run方法里面。Thread类实际上也是实现了Runnable接口的类。
Thread和Runnable的区别
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
实现Runnable接口比继承Thread类所具有的优势:
适合多个相同的程序代码的线程去共享同一个资源。
可以避免java中的单继承的局限性。
增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和数据独立。
线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类。
匿名内部类方式实现线程的创建
public class Demo {
public static void main(String[] args) {
//使用匿名内部类方法;直接创建Thread类的子类对象
/*
* new Thread() { public void run() { for (int i = 0; i < 10; i++) {
* System.out.println("新线程正在执行" + i); } } }.start();
*/
//使用匿名内部类方式;直接创建Runnable接口实现类对象
Runnable r = new Runnable() {
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("新线程正在执行" + i);
}
}
};
new Thread(r).start();
for (int i = 0; i < 10; i++) {
System.out.println("main线程正在执行" + i);
}
}
}
线程安全
两个或两个以上的线程在访问共享资源时,仍然能得到正确的结果则称之为线程安全
模拟卖50张电影票
public class Ticket implements Runnable {
private int ticket = 50;
// 买票操作
@Override
public void run() {
// 每个窗口买票操作,窗口永远开启
while (true) {
if (ticket > 0) {
// 使用sleep方法模拟买票
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 获取当前对象的名字
String name = Thread.currentThread().getName();
System.out.println(name + "正在卖票:" + ticket--);
}
}
}
}
测试类:
public class Demo {
public static void main(String[] args) {
// 创建线程任务对象
Ticket ticket = new Ticket();
// 创建三个窗口卖票
Thread t1 = new Thread(ticket, "窗口一");
Thread t2 = new Thread(ticket, "窗口二");
Thread t3 = new Thread(ticket, "窗口三");
// 同时开始卖票
t1.start();
t2.start();
t3.start();
}
}
结果出现了这种现象:
这种问题,几个窗口(线程)票数不同步了,称为线程不安全
线程同步
当我们使用多个线程访问统一资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题.
要解决上述多线程并发访问多一个资源的安全性问题,java中提供了同步机制(synchronized)来解决,有三种方式完成同步操作:
同步代码块
同步方法
锁机制
同步代码块
同步代码块:synchronized关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问
synchronized(同步锁){
需要同步操作的代码
}
同步锁注意事项 1.锁对象可以是任意类型。 2.多个线程对象要使用同一把锁。
同步代码块实现线程安全
public class Ticket implements Runnable {
private int ticket = 50;
Object lock = new Object();
// 买票操作
@Override
public void run() {
// 每个窗口买票操作,窗口永远开启
while (true) {
synchronized (lock) {
if (ticket > 0) {
// 使用sleep方法模拟买票
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 获取当前对象的名字
String name = Thread.currentThread().getName();
System.out.println(name + "正在卖票:" + ticket--);
}
}
}
}
}
同步方法
同步方法:使用synchronized修饰的方法,就叫做同步方法保证A线程执行该方法的时候,其他线程只能在方法外等着
public synchronized void method(){
可能会产生线程安全问题的代码
}
同步方法实现线程安全
public class Ticket implements Runnable {
private int ticket = 50;
// 买票操作
@Override
public void run() {
// 每个窗口买票操作,窗口永远开启
while (true) {
sellTicket();
}
}
// 锁对象是谁调用这个方法就是谁,this
public synchronized void sellTicket() {
if (ticket > 0) {
// 使用sleep方法模拟买票
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 获取当前对象的名字
String name = Thread.currentThread().getName();
System.out.println(name + "正在卖票:" + ticket--);
}
}
}
Lock锁
java.util.concurrent.locks.Lock 机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作,同步代码块/同步方法具有的功能Lock都有,除此之外更强大,更体现面向对象。 Lock常用方法
public void lock():加同步锁。
public void unlock():释放同步锁。
Lock锁实现线程安全
public class Ticket implements Runnable {
private int ticket = 50;
Lock lock = new ReentrantLock();
// 买票操作
@Override
public void run() {
// 每个窗口买票操作,窗口永远开启
while (true) {
lock.lock();
if (ticket > 0) {
// 使用sleep方法模拟买票
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 获取当前对象的名字
String name = Thread.currentThread().getName();
System.out.println(name + "正在卖票:" + ticket--);
}
lock.unlock();
}
}
}
线程池
线程池:其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。
线程池能够带来三个好处:
降低资源消耗。减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
提高线程的可管理性。可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存
线程池的使用
Java里面线程池的顶级接口是java.util.concurrent.Executors
public static ExecutorService newFixedThreadPool(int nThreads) :返回线程池对象。(创建的是有界线程池,也就是池中的线程个数可以指定最大数量)
public Future<?> submit(Runnable task) :获取线程池中的某一个线程对象,并执行
Runnable实现类代码:
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("我要一个教练");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("教练来了: " + Thread.currentThread().getName());
System.out.println("教我游泳,交完后,教练回到了游泳池");
}
}
线程池测试类:
public class Demo{
public static void main(String[] args) {
// 创建线程池对象
ExecutorService service = Executors.newFixedThreadPool(2);//包含2个线程对象
// 创建Runnable实例对象
MyRunnable r = new MyRunnable();
//自己创建线程对象的方式
// Thread t = new Thread(r);
// t.start(); ---> 调用MyRunnable中的run()
// 从线程池中获取线程对象,然后调用MyRunnable中的run()
service.submit(r);
// 再获取个线程对象,调用MyRunnable中的run()
service.submit(r);
service.submit(r);
// 注意:submit方法调用结束后,程序并不终止,是因为线程池控制了线程的关闭。
// 将使用完的线程又归还到了线程池中
// 关闭线程池
//service.shutdown();
}
}
java_线程、同步、线程池的更多相关文章
- 线程同步&线程池
线程同步&线程池 线程同步 线程不同步会出现的问题: 当多个线程操作同一资源时,会出现重复操作和和操作不存在的资源的问题,为了规避这一问题就需要线程的同步操作来实现资源的共同使用. 线程同步: ...
- 线程:主线程、子线程 同步线程、异步线程 单线程、多线程 System.Threading与System.Windows.Threading
入门-------------------------------------------------------------------------------- 概述与概念 一个C#程序开始 ...
- Python并发编程-线程同步(线程安全)
Python并发编程-线程同步(线程安全) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 线程同步,线程间协调,通过某种技术,让一个线程访问某些数据时,其它线程不能访问这些数据,直 ...
- Qt QThread 线程创建,线程同步,线程通信 实例
1. 继承QThread, 实现run()方法, 即可创建线程. 2. 实例1 代码 myThread.h #ifndef MYTHREAD_H #define MYTHREAD_H #includ ...
- C#线程同步--线程通信
问题抽象:当某个操作的执行必须依赖于另一个操作的完成时,需要有个机制来保证这种先后关系.线程通信方案:ManualResetEventSlim.ManualResetEvent.AutoResetEv ...
- 细说C#多线程那些事 - 线程同步和多线程优先级
上个文章分享了一些多线程的一些基础的知识,今天我们继续学习. 一.Task类 上次我们说了线程池,线程池的QueueUserWorkItem()方法发起一次异步的线程执行很简单 但是该方法最大的问题是 ...
- C#并行编程(6):线程同步面面观
理解线程同步 线程的数据访问 在并行(多线程)环境中,不可避免地会存在多个线程同时访问某个数据的情况.多个线程对共享数据的访问有下面3种情形: 多个线程同时读取数据: 单个线程更新数据,此时其他线程读 ...
- Linux多线程编程——多线程与线程同步
多线程 使用多线程好处: 一.通过为每种事件类型的处理单独分配线程,可以简化处理异步事件的代码,线程处理事件可以采用同步编程模式,启闭异步编程模式简单 二.方便的通信和数据交换 由于进程之间具有独立的 ...
- java SE学习之线程同步(详细介绍)
java程序中可以允许存在多个线程,但在处理多线程问题时,必须注意这样一个问题: 当两个或多个线程同时访问同一个变量,并且一些线程需要修改这个变量时,那么这个 ...
- Java之线程,常用方法,线程同步,死锁
1, 线程的概念 进程与线程 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程.(进程是资源分配的最小单位) 线程:同一类线程共享代码和数据 ...
随机推荐
- Django之 Models组件
本节内容 路由系统 models模型 admin views视图 template模板 引子 讲django的models之前, 先来想一想, 让你通过django操作数据库,你怎么做? 做苦思冥想, ...
- Python并发编程05 /死锁现象、递归锁、信号量、GIL锁、计算密集型/IO密集型效率验证、进程池/线程池
Python并发编程05 /死锁现象.递归锁.信号量.GIL锁.计算密集型/IO密集型效率验证.进程池/线程池 目录 Python并发编程05 /死锁现象.递归锁.信号量.GIL锁.计算密集型/IO密 ...
- Linux如何用脚本监控Oracle发送警告日志ORA-报错发送邮件
Linux如何用脚本监控Oracle发送警告日志ORA-报错发送邮件 前言 公司有购买的监控软件北塔系统监控,由于购买的版权中只包含了有限台数据库服务器的监控,所以只监控了比较重要的几台服务器. 后边 ...
- oracle 12c数据库在Windows环境下的安装
因为菜鸟小白之前做着一些数据库审计产品的测试,接下来我会分享一些关于数据库安装和通过python的访问数据库的知识 安装 首先我们需要下载一个oracle 12c的安装程序,解压后右键点击“ ...
- 用maven打包java项目的pom文件配置
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...
- servlet的HttpSession与HibernateSession的区别
一.javax.servlet.http.HttpSession是一个抽象接口 它的产生:J2EE的Web程序在运行的时候,会给每一个新的访问者建立一个HttpSession,这个Session是用户 ...
- 基于python的自动化测试简介【十年从业大佬】
一.自动化测试包括以下几个方面: 1. 常用测试工具: (1)QTP:主要用于回归测试和测试同一软件的新版本 (2)Robot Framwork:python编写的功能自动化测试框架,具有良好的可扩展 ...
- 详解UDP协议
运输层位于网络层之上,网络层提供了主机之间的逻辑通信:而运输层为运行在不同主机上的应用进程之间提供了逻辑通信.从应用程序角度看,通过逻辑通信,运行不同进程的主机好像直接相连一样.应用进程使用运输层提供 ...
- X-Tag实战:给博客加一个隐藏侧栏的功能
X-Tag是什么? X-Tag是一个库,这个库可以让你用面向对象的方式定义自定义标签并给与其功能,很适合用来写一些网页小组件. xtag.create('x-clock', class extends ...
- NameBeta - 多家比价以节省咱的域名注册成本
共收录 1584 种顶级域名,汇集互联网上 29 家知名域名注册商,每日更新价格信息 有的域名还可以查出到期时间点我前往官网 NameSilo1美元优惠码:whatz