Java多线程基础(二)
1.多线程数据安全
线程同步:多个线程需要访问同一资源时,需要以某种顺序来确定该资源某一时刻只能被一个线程使用。从而,解决并发操作可能带来的异常。
2.同步代码块实现同步(部分代码的访问,我们希望它同步)
synchronized(lock){
//同步代码块
}
其中lock就是同步监视器,它的含义是:线程开始执行同步代码块之前,必须先获得对同步监视器的锁定。任何时刻只能有一个线程可以获得对同步监视器的锁定,当同步代码块执行完成后,该线程会释放对该同步监视器的锁定。虽然java程序允许使用任何对象作为同步监视器,但是同步监视器的目的就是为了阻止两个线程对同一个共享资源进行并发访问,因此通常使用可能被并发访问的共享资源充当同步监视器。
下面的实例可方便理解:
package com.test; public class ThreadDemo1 { public static void main(String[] args) {
// TODO Auto-generated method stub
//创建共享资源对象
TicketRes ticketRes=new TicketRes();
//创建线程对象
Thread w1=new Thread(ticketRes,"窗口1");
Thread w2=new Thread(ticketRes,"窗口2");
Thread w3=new Thread(ticketRes,"窗口3");
w1.start();
w2.start();
w3.start();
}
}
//共享资源类
class TicketRes implements Runnable{
private int ticket=100;
private Object lock=new Object();//锁 @Override
public void run() {
// TODO Auto-generated method stub
while(true) {
synchronized (lock) {
if(ticket>=1) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖第"+ticket+"张票");
ticket--;
}else {
break;
}
}
}
}
}
3.同步方法实现同步(强调功能,方法的访问是同步的)
同步方法就是使用synchronized关键字修饰某个方法,用synchronized修饰的方法就是同步方法。这个同步方法(非static方法)无须显式指定同步监视器,同步方法的同步监视器是this,也就是调用该方法的对象,通过同步方法可以非常方便的实现线程安全的类。
下面的实例可方便理解:
package com.test; public class ThreadDemo2 { public static void main(String[] args) {
// TODO Auto-generated method stub
//创建共享资源对象
TicketRes1 ticketRes=new TicketRes1();
//创建线程对象
Thread w1=new Thread(ticketRes,"窗口1");
Thread w2=new Thread(ticketRes,"窗口2");
Thread w3=new Thread(ticketRes,"窗口3");
w1.start();
w2.start();
w3.start();
}
}
//共享资源类
class TicketRes1 implements Runnable{
private static int ticket=100;
private Object lock=new Object();//锁 @Override
public void run() {
// TODO Auto-generated method stub
while(true) {
if(!TicketRes1.saleTicket()) {
break;
}
}
}
public synchronized static boolean saleTicket() {
if(ticket>=1) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖第"+ticket+"张票");
ticket--;
return true;
}else {
return false;
}
}
}
4.锁的概念以及死锁问题
多线程在运行的时候可能会遇到这样的问题,多个线程要用到同一个资源,那可能会出现错乱,比如线程要改动资源里的数据,那么多个线程同时改就乱了套了。就像公共厕所,必须要一个一个接着上,不能两个人或者多个人同时上。那么锁这个概念就是像上厕所的门,一个人在上厕所,锁上了门,那下一个人就不能进去了。同样的,如果我们想让某一个程序或者某一个变量只能同时被一个线程运行,就得给程序上锁。所以上了锁,就能保证线程有秩序地运行。
当两个线程相互等待对方释放同步监视器时就会发生死锁,Java虚拟机没有检测,也没有采取措施来处理死锁情况,所以多线程编程时应该采取措施避免死锁出现。一旦出现死锁,程序既不会发生任何异常,也不会给出任何提示,只是所有线程都处于阻塞状态,无法继续。
接下来看一个死锁的Java实例(是不是停不下来了,就相当于循环语句的死循环)
package com.test; public class DeadLock { public static void main(String[] args) {
// TODO Auto-generated method stub
DeadLockThread he=new DeadLockThread(true,"小明");//他
DeadLockThread she=new DeadLockThread(false,"小华 ");//她
he.start();
she.start();
}
}
//线程
class DeadLockThread extends Thread{
boolean flag=false;
public DeadLockThread() { }
protected DeadLockThread(boolean flag,String name) {
super(name);
this.flag=flag;
}
public void run() {
while(true) {
if(flag) {
synchronized (Lock.locka) {//他
System.out.println(Thread.currentThread().getName()+"抢到了locka");
}
synchronized (Lock.lockb) {
System.out.println(Thread.currentThread().getName()+"抢到了lockb");
System.out.println(Thread.currentThread().getName()+"可以上厕所了"); }
}else {
synchronized (Lock.lockb) {//她
System.out.println(Thread.currentThread().getName()+"抢到了lockb");
}
synchronized (Lock.locka) {
System.out.println(Thread.currentThread().getName()+"抢到了locka");
System.out.println(Thread.currentThread().getName()+"可以上厕所了");
}
}
}
}
}
//创建锁对象
class Lock{
public static Object locka=new Object();
public static Object lockb=new Object();
}
5.线程终止
1.使用标志,使run()方法正常执行完毕
package com.test; import java.util.Scanner; public class Demo1 { public static void main(String[] args) {
// TODO Auto-generated method stub
FlagStop flagStop=new FlagStop("线程1");
flagStop.start();
Scanner input=new Scanner(System.in);
System.out.println("输入任意字符结束主线程");
input.next();
flagStop.flag=false;//主线程修改其他线程的变量
System.out.println("主线程结束");
} }
class FlagStop extends Thread{
//定义标志 volatile:易挥发的、不稳定的,使用volatile修饰后,获取变量不会从缓存中取,从内存中取。
volatile boolean flag=true;
public FlagStop() {
// TODO Auto-generated constructor stub
} public FlagStop(String name) {
super(name);
// TODO Auto-generated constructor stub
} @Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName()+"开始执行了");
while(flag) { }
System.out.println(Thread.currentThread().getName()+"执行完毕");
}
}
2.使用stop方法强制终止线程
package com.test; import java.util.Scanner; public class Demo2 { public static void main(String[] args) {
// TODO Auto-generated method stub
WordStop wordStop=new WordStop("线程1");
wordStop.start();
Scanner input=new Scanner(System.in);
System.out.println("输入任意字符结束主线程");
input.next();
wordStop.stop();
wordStop.flag=false;//主线程修改其他线程的变量
System.out.println("主线程结束");
} }
class WordStop extends Thread{
//定义标志 volatile:易挥发的、不稳定的,使用volatile修饰后,获取变量不会从缓存中取,从内存中取。
volatile boolean flag=true;
public WordStop() {
// TODO Auto-generated constructor stub
} public WordStop(String name) {
super(name);
// TODO Auto-generated constructor stub
} @Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName()+"开始执行了");
while(flag) { }
System.out.println(Thread.currentThread().getName()+"执行完毕");
}
}
3.使用interrupt方法中断线程
package com.test; import java.io.IOException; public class Demo3 { public static void main(String[] args) throws IOException, InterruptedException {
// TODO Auto-generated method stub
InterruptStop interruptStop=new InterruptStop();
interruptStop.start();
System.out.println("在10秒之内输入任意符号结束");
System.in.read();
interruptStop.interrupt();//打断正在休眠的线程
interruptStop.join();
System.out.println("主线程结束...");
}
}
class InterruptStop extends Thread{
@Override
public void run() {
try {
Thread.sleep(10000);//抛出一个异常InterruptedException
} catch (InterruptedException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
System.out.println("执行了catch");
}
System.out.println("子线程执行完毕");
}
}
6.线程间通信
1.wait:挂起当前线程,释放共享资源锁
2.notify:在所有的wait线程当中随机选择一条唤醒
3.notifyAll:唤醒全部wait线程
Java多线程基础(二)的更多相关文章
- java多线程基础(二)--java多线程的基本使用
java多线程的基本使用 在java中使用多线程,是通过继承Thread这个类或者实现Runnable这个接口或者实现Callable接口来完成多线程的. 下面是很简单的例子代码: package c ...
- Java多线程基础(二)
信号量Semaphore,类似于锁的功能,用于多线程中对一组资源的控制. acquire方法用于尝试获取一个资源,未获取前将一直等待.release用于释放一个资源,release的前提是已经获得了一 ...
- Java 多线程基础(十二)生产者与消费者
Java 多线程基础(十二)生产者与消费者 一.生产者与消费者模型 生产者与消费者问题是个非常典型的多线程问题,涉及到的对象包括“生产者”.“消费者”.“仓库”和“产品”.他们之间的关系如下: ①.生 ...
- [转]Java多线程干货系列—(一)Java多线程基础
Java多线程干货系列—(一)Java多线程基础 字数7618 阅读1875 评论21 喜欢86 前言 多线程并发编程是Java编程中重要的一块内容,也是面试重点覆盖区域,所以学好多线程并发编程对我们 ...
- Java多线程基础:进程和线程之由来
转载: Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够 ...
- Java 多线程——基础知识
java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...
- Java多线程(二)关于多线程的CPU密集型和IO密集型这件事
点我跳过黑哥的卑鄙广告行为,进入正文. Java多线程系列更新中~ 正式篇: Java多线程(一) 什么是线程 Java多线程(二)关于多线程的CPU密集型和IO密集型这件事 Java多线程(三)如何 ...
- 1、Java多线程基础:进程和线程之由来
Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够融会贯通 ...
- Java 多线程基础(一)基本概念
Java 多线程基础(一)基本概念 一.并发与并行 1.并发:指两个或多个事件在同一个时间段内发生. 2.并行:指两个或多个事件在同一时刻发生(同时发生). 在操作系统中,安装了多个程序,并发指的是在 ...
- Java 多线程基础(三) start() 和 run()
Java 多线程基础(三) start() 和 run() 通过之前的学习可以看到,创建多线程过程中,最常用的便是 Thread 类中的 start() 方法和线程类的 run() 方法.两个方法都包 ...
随机推荐
- Python内置函数(40)——map
英文文档: map(function, iterable, ...) Return an iterator that applies function to every item of iterabl ...
- bootcamp分区_BOOTCAMP 删除分区失败
mac 装了双系统,Mac OS X 分配的内存太少了,导致使用卡顿,要删掉windows系统. 在删除windows的时候出现 “您的磁盘不能恢复为单一的分区” 解决方案: 1.重启Mac,并按下 ...
- SpringCloud(2)---SpringCloud入门篇
SpringCloud理解篇 一.微服务概述 1.什么是微服务 目前的微服务并没有一个统一的标准,一般是以业务来划分将传统的一站式应用,拆分成一个个的服务,彻底去耦合,一个微服务就是单功能业务,只做一 ...
- asp.net core系列 41 Web 应用 MVC视图
一.MVC视图 在Web开发的MVC和Razor中,都有使用视图,在Razor中称为"页"..cshtml视图是嵌入了Razor标记的HTML模板. Razor 标记使用C#代码, ...
- hibernate易混淆点
萌新小笔记: 用过hibernate的小伙伴肯定经常看到这几个东西吧!但是初学者常常会把这几个搞不清楚:dataSource,session,sessionFactory(dataSource),hi ...
- 使用mpvue开发小程序教程(六)
在上一章节中,我们列举了在Vue中能用但在mpvue中不能用或需要特别注意的特性,在实际开发前了解一下还是很有必要的,可以避免浪费找错误的时间. 如果你使用过原生的小程序框架,你一定经历过或思考过怎么 ...
- Linux服务器时间相关命令记录
前言 以往安装服务器时间都是正常,但是最近服务器的时间经常出现问题,所以在安装配置完成服务器之后需要对服务器的时间进行测试,如果服务器时间异常,那么当程序去取系统时间的时候就会出现问题. 时间相关命令 ...
- 2018年Fintech金融科技关键词和入行互金从业必懂知识
2018年过去大半,诸多关键词进入眼帘: 5G,消费降级,数据裸奔,新零售,AI,物联网,云计算,合规监管,风控,割韭菜,区块链,生物识别,国民空闲时间以及金融科技. 这些词充斥着我们的生活和时间,而 ...
- kubernetes进阶之一:简单例子
kubernetes 从一个简单例子开始 参考 <kubernetes 权威指南>一节的 从一个简单例子开始,操作实录. 一.Java Web 应用结构 二.启动MySql服务 1.首先为 ...
- windows查看端口占用 windows端口占用 查找端口占用程序 强制结束端口占用 查看某个端口被占用的解决方法 如何查看Windows下端口占用情况
windows下查询端口占用情况 ,强制结束端口占用程序 查询8080端口被那个程序占用 如何强制结束windows下端口占用情况? 下面操作在win10下 在控制台执行命令 1.列出所有端口的情 ...