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() 方法.两个方法都包 ...
随机推荐
- C#基础语法
究极入门之Hello world static void Main(string[] args) { //你好,世界 Console.WriteLine("HELLO WORLD" ...
- jQuery Mobile中表单的使用体会
jQuery Mobile是手机端(移动端)页面制作用的框架,包括CSS和JavaScript,此处简单总结一下表单的书写,主要涉及CSS部分.框架提供了表单的一些样式,但在实际使用的时候,我们可能会 ...
- IntelliJ IDEA 自定义方法注解模板
最近没啥事开始正式用Eclipse 转入 idea工具阵营,毕竟有70%的开发者在使用idea开发,所以它的魅力可想而知.刚上手大概有一天,就知道它为啥取名为 intelli(智能化)了,确实很智能, ...
- .NET Core实战项目之CMS 第七章 设计篇-用户权限极简设计全过程
写在前面 这篇我们对用户权限进行极简设计并保留其扩展性.首先很感谢大家的阅读,前面六章我带着大家快速入门了ASP.NET Core.ASP.NET Core的启动过程源码解析及配置文件的加载过程源码解 ...
- asp.net core系列 31 EF管理数据库架构--必备知识 反向工程
一. 反向工程 反向工程是基于数据库架构,生成的实体类和DbContext类代码的过程,对于Visual Studio开发,建议使用PMC.对于其他开发环境,请选择.NET Core CLI工具( ...
- arrays.xml中使用integer-array引用drawable图片资源,代码中如何将这些图片资源赋值到ImageView控件中
当我们在arrays.xml文件中声明一些图片资源数组的时候: <?xml version="1.0" encoding="utf-8"?> < ...
- 使用docker-compose来部署开发环境
docker-compose的作用 docker-comopse可以帮助我们快速搭建起开发环境,比如你可以去把redis,mongodb,rabbitmq,mysql,eureka,configser ...
- HotSpot虚拟机对象相关内容
一.对象的创建 1.类加载检查 普通对象的创建过程:虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载.解析和初始化 ...
- HashMap,HashTable,ConcurrentHashMap异同比较
0. 前言 HashMap和HashTable的区别一种比较简单的回答是: (1)HashMap是非线程安全的,HashTable是线程安全的. (2)HashMap的键和值都允许有null存在,而H ...
- C#线程安全使用(三)
在讲CancellationTokenSource之前我决定先讲一下lock和Interlocked,如果能很好的理解这两个,再去理解CancellationTokenSource就会方便很多,由于我 ...