java基础(10) -线程
线程
相当于轻量级进程,线程在程序中是独立的、并发的执行路径,每个线程有它自己的堆栈、自己的程序计数器和自己的局部变量。但是,与分隔的进程相比,进程中的线程之间的隔离程度要小。它们共享内存、文件句柄和其它每个进程应有的状态。
构建一个线程
//创建一个新线程 参数为实现了 Runnable 接口的类实例
Thread t = new Thread(run);
//启动线程
t.start();
线程终止
- run方法完成自动退出
- 一个没有捕获的异常终止了run方法而意外死亡
- stop方法 已弃用
- interrupt方法,重设中断状态,发出中断请求,如果该线程被sleep调用阻塞会抛出异常InterruptedException
线程状态
- New 创建
- Runnable 可运行
- Blocked 被阻塞
- Waiting 等待
- Timed waiting 计时等待
- Terminated 被终止
抢占式调度
一个进程处于Runnable状态,也可能没有运行,取决于操作系统给时间提供的运行时间
线程让步
暂停当前正在执行的线程对象,让其他线程先执行,
实际中无法保证yield()达到让步目的,
因为让步的线程还有可能被线程调度程序再次选中。
守护线程
t.setDaemon(true);
注意:
不要直接调用run方法,这样不能启动新线程,当设计多线程应用程序的时候,一定不要依赖于线程的优先级,因为线程调度优先级操作是没有保障的,只能把线程优先级作用作为一种提高程序效率的方法,但是要保证程序不依赖这种操作。
demo
public class MyRunnable implements Runnable {
public String name = null;
@Override
public void run() {
for(int i =0;i<100;i++){
// try {
// Thread.sleep(3);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
System.out.println(i + name);
}
}
public static void main(String[] args) {
MyRunnable run = new MyRunnable();
run.name = "aaaa";
MyRunnable run2 = new MyRunnable();
run2.name = "bbbbb";
Thread t = new Thread(run);
Thread t2 = new Thread(run2);
/**
* 设置优先级 1~10
* Thread.MAX_PRIORITY
* Thread.NORM_PRIORIT
* Thread.MIN_PRIORITY
*/
t.setPriority(8);
/**
* 设置一个线程异常处理器
*/
t.setUncaughtExceptionHandler(new MyErrorHandler());
/**
* 启动线程
*/
t.start();
/**
* 等调用join的线程执行完成再执行下面接着的线程
*/
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
/**
* 设为守护线程 要在线程启动前调用
*/
t2.setDaemon(true);
t2.start();
//用以判断当前线程是否为中断状态
Thread.currentThread().isInterrupted();
/**
* 线程让步
* 暂停当前正在执行的线程对象,让其他线程先执行,
* 实际中无法保证yield()达到让步目的,
* 因为让步的线程还有可能被线程调度程序再次选中。
*/
Thread.yield();
}
}
//异常处理器
public class MyErrorHandler implements UncaughtExceptionHandler {
/**
* 这里可以做任何针对异常的处理,比如记录日志等等
*/
public void uncaughtException(Thread a, Throwable e) {
System.out.println("This is:" + a.getName() + ",Message:"
+ e.getMessage());
e.printStackTrace();
}
}
同步
/**
当多个线程操作同一个对象时,容易出现数据异常状态,
具体原因是当一个线程获取了所需要的参数,准备赋值时等待,
另外一个线程也获取了所需要的参数进行了赋值
这时第一个赋值被唤醒,其值会覆盖第二个线程的值
*/
public class HeroProperties {
public int mana = 1000;
public void useSkill(){
mana -= 10;
System.out.println("剩余蓝:" + mana);
}
}
public class SyncRunnable implements Runnable{
public SyncRunnable(HeroProperties hero){
this.hero = hero;
}
public HeroProperties hero;
@Override
public void run() {
hero.useSkill();
}
public static void main(String[] args) {
HeroProperties hero = new HeroProperties();
for(int i=0;i<1000;i++){
SyncRunnable r = new SyncRunnable(hero);
Thread t = new Thread(r);
t.start();
}
}
}
/*
打印的结果:出现重复数据
剩余蓝:980
剩余蓝:960
剩余蓝:970
剩余蓝:980
剩余蓝:940
剩余蓝:950
剩余蓝:930
剩余蓝:920
...
剩余蓝:-100
剩余蓝:-110
*/
锁对象-ReentrantLock
使用锁对象 使赋值的代码块变为同步
/**
创建锁
Lock lock = new ReentrantLock();
锁
lock.lock();
解锁
lock.unLock();
*/
public class HeroProperties {
public int mana = 1000;
public Lock lock = new ReentrantLock();
public void useSkill(){
//锁
lock.lock();
mana -= 10;
System.out.println("剩余蓝:" + mana);
//解锁
lock.unlock();
}
}
/*
打印结果没有出现重复值
剩余蓝:990
剩余蓝:980
剩余蓝:970
剩余蓝:960
剩余蓝:950
剩余蓝:940
剩余蓝:930
剩余蓝:920
...
剩余蓝:-100
剩余蓝:-110
*/
条件锁-Condition
此时值出现负数是异常的,mana要大于0才能使用skill,要添加一个条件使mana小于0时进行等待mana的恢复,恢复之后再继续使用skill,此时就要使用条件锁,不符合条件是线程进入等待,又不会造成死锁。
/**
Lock lock = new ReentrantLock();
Condition cd = lock.newCondition();
//该条件不满足时调用await,线程进入等待
cd.await();
//其他线程执行完之后 激活所有等待的线程
cd.signalAll();
//激活随机一条线程
cd.signal();
*/
/**
Lock lock = new ReentrantLock();
Condition cd = lock.newCondition();
//该条件不满足时调用await,线程进入等待
cd.await();
//其他线程执行完之后 激活所有等待的线程
cd.signalAll();
//激活随机一条线程
cd.signal();
*/
public class HeroProperties {
public int mana = 100;
public Lock lock = new ReentrantLock();
public Condition cd = lock.newCondition();
public void useSkill() throws InterruptedException{
lock.lock();
//自然恢复的蓝量
mana+=1;
System.out.println(Thread.currentThread() +"尝试使用技能---------"+ "蓝量:"+mana);
if(mana<10) {
System.out.println(Thread.currentThread() +"ZZZZZZZZZZZZ"+"线程睡眠");
cd.await();
}
//有可能是被唤醒的线程
if(mana<10) {
//尝试唤醒的时候不一定能直接运行,也有可能被其他线程执行了操作导致该线程操作失败
System.out.println(Thread.currentThread() +"随机唤醒的线程不符合条件");
}else{
//蓝条刚好只剩下一次的时候吃药
boolean isUseItem = (mana==10);
System.out.println(Thread.currentThread() + "蓝量:" + mana);
mana -= 10;
System.out.println(Thread.currentThread() + "使用技能后剩余蓝:" + mana);
if(isUseItem) {
mana += 30;
System.out.println("吃药恢复30");
}
if(mana>=10) {
//唤醒所有线程
//cd.signalAll();
//随机唤醒一个线程
cd.signal();
}
}
lock.unlock();
}
}
synchronized
可以在方法名添加 synchronized 关键字实现同步
/**
* wait() 线程进入等待
* notify() 随机唤醒一个线程
* notifyAll() 唤醒所有线程
*/
public synchronized void useSkill(){
//do something
//wait();
}
同步阻塞,synchronized一个对象组成一个代码块,该代码块就能实现同步
Object lock = new Object()
public void useSkill(){
synchronized(obj){
//do something
}
}
java基础(10) -线程的更多相关文章
- 【Java基础】线程和并发机制
前言 在Java中,线程是一个很关键的名词,也是很高频使用的一种资源.那么它的概念是什么呢,是如何定义的,用法又有哪些呢?为何说Android里只有一个主线程呢,什么是工作线程呢.线程又存在并发,并发 ...
- Java基础-多线程-③线程同步之synchronized
使用线程同步解决多线程安全问题 上一篇 Java基础-多线程-②多线程的安全问题 中我们说到多线程可能引发的安全问题,原因在于多个线程共享了数据,且一个线程在操作(多为写操作)数据的过程中,另一个线程 ...
- Java基础篇——线程、并发编程知识点全面介绍(面试、学习的必备索引)
原创不易,如需转载,请注明出处https://www.cnblogs.com/baixianlong/p/10739579.html,希望大家多多支持!!! 一.线程基础 1.线程与进程 线程是指进程 ...
- Java基础_线程的使用及创建线程的三种方法
线程:线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. 进程:进 ...
- Java基础之线程——使用执行器(UsingExecutors)
控制台程序. 在这个版本的银行示例中,把借款和贷款事务创建为在不同线程中执行的任务,它们把事务提交给职员.创建事务的任务是Callable<>任务,因为它们需要返回已为每个账户创建的借款或 ...
- Java基础10:全面解读Java异常
更多内容请关注微信公众号[Java技术江湖] 这是一位阿里 Java 工程师的技术小站,作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux ...
- Java基础8-多线程;同步代码块
作业解析 利用白富美接口案例,土豪征婚使用匿名内部类对象实现. interface White{ public void white(); } interface Rich{ public void ...
- Java基础-多线程-①线程的创建和启动
简单阐释进程和线程 对于进程最直观的感受应该就是“windows任务管理器”中的进程管理: (计算机原理课上的记忆已经快要模糊了,简单理解一下):一个进程就是一个“执行中的程序”,是程序在计算机上的一 ...
- java基础25 线程的常用方法、线程安全问题、死锁现象
一.线程的常用方法 1.Thread(String name):初始化线程的名字2. setName(String name):设置线程的名字3. getName():返回线程的名字4. sleep( ...
随机推荐
- 使用函数指针调用C++虚函数
基本概念: 1. 函数指针,一个地址指针变量,其值指向代码区的某个函数首地址. 2. 虚函数,可以被子类覆写的C++成员函数.由虚函数表实现. 3. 虚函数表指针(vpt),指向虚函数表首地址的指针, ...
- EMC在线测试题目及答案 绿色为正确答案,红色为错误答案
1. 以下哪一项技术可以将IT的物理资源放在一个共享池中以及提升它们的利用率? 分区 虚拟化 协调 LUN 屏蔽 2. 哪一项是EMC的基于块-存储(block-based)的高端存储? Atmos ...
- 写给Android App开发人员看的Android底层知识(3)
(七)App启动流程第2篇 书接上文,App启动一共有七个阶段,上篇文章篇幅所限,我们只看了第一阶段,接下来讲剩余的六个阶段,仍然是拿斗鱼App举例子. 简单回顾一下第一阶段的流程,就是Launche ...
- 关于QT按键信号槽的总结(原创)
QT界面按钮一般是必填的: 每个按钮都要 Go to slot 下面有几个都是常用的,先说一下 clicked:pressed:releaed的区别 字面意思看:click是点击一下,pressed是 ...
- aws上redhat安装redis服务记
1.准备 官网下载
- 探讨SQL Server并发处理队列数据不阻塞解决方案
前言 之前对于并发这一块确实接触的比较少,自从遇到现在的老大,每写完一块老大都会过目一下然后给出意见,期间确实收获不少,接下来有几篇会来讲解SQL Server中关于并发这一块的内容,有的是总结,有的 ...
- Django学习报错记录
1. 运行manage.py任务 makemigrations时,报错: doesn't declare an explicit app_label and isn't in an applicat ...
- ES6核心内容精讲--快速实践ES6(三)
Promise 是什么 Promise是异步编程的一种解决方案.Promise对象表示了异步操作的最终状态(完成或失败)和返回的结果. 其实我们在jQuery的ajax中已经见识了部分Promise的 ...
- CentOS下SparkR安装部署:hadoop2.7.3+spark2.0.0+scale2.11.8+hive2.1.0
注:之前本人写了一篇SparkR的安装部署文章:SparkR安装部署及数据分析实例,当时SparkR项目还没正式入主Spark,需要自己下载SparkR安装包,但现在spark已经支持R接口,so更新 ...
- String为值类型还是引用类型
关于String为值类型还是引用类型的讨论一直没有平息,最近一直在研究性能方面的问题,今天再次将此问题进行一次明确.希望能给大家带来点帮助. 如果有错误请指出. 来看下面例子: //值类型 int a ...