java线程基础知识----线程与锁
我们上一章已经谈到java线程的基础知识,我们学习了Thread的基础知识,今天我们开始学习java线程和锁。
1. 首先我们应该了解一下Object类的一些性质以其方法,首先我们知道Object类的是java的顶层类,所有的类都集成自Object类,包括string和数组。而且每一个Object都有一个锁,同一时间只能有一个线程暂用这个对象的锁。这是我们今天学习的前提条件,至于Object的一些方法我们在后面的章节中会进行学习。
2. java锁之synchronized: 想必大家都知道java的synchronized关键字,在我看来这是锁操作中相对简单的方法,但是对事物我总有一个定义“简单的就是可扩展性差的”,下面我们将了解synchronized关键字的用法:
A. 入门基础实例: 举一个经典的售票例子,就是同时有2个窗口售票(当然是电子票),而且票的数量是一定的,假设20张。两个窗口之间售票相互独立。我们应该怎么实现?
public class ThreadTest {
public static void main(String[] args) throws InterruptedException{
Thread1 thread1 = new Thread1();
Thread threadA = new Thread(thread1);
Thread threadB = new Thread(thread1);
threadA.start();
threadB.start();
}
}
class Thread1 implements Runnable{
private Integer ticket = 100;
public void run(){
while ((ticket--) >0) {
System.out.println("窗口"+Thread.currentThread().getName()+"卖票,当前票的数量为"+ticket);
}
}
}
计算结果: 具有随机性和不唯一性
显然这样的结果并不是我们想要的,这里我们先分析一下原因,为什么会导致这种计算结果?在访问临界区资源的时候我们并没有控制进入临界区的线程数量,也就是说我们在这个过程中可能有两个线程同时进入了这段"临界区",访问了"临界资源"。假设有两个线程同时访问到了ticket值为100,但是两个线程都进行了--操作,导致本来线程应该为98的,但是实际结果确实99。这其实就是线程不安全的。
那么我们如何更改上面的程序进行更改呢?我们只需要引入synchronized关键字,首先我们说一下synchronized方法的两种使用方式:
一: synchronized代码块:如上面的程序只需要进行如下更改即可:
public class ThreadTest {
public static void main(String[] args) throws InterruptedException{
Thread1 thread1 = new Thread1();
Thread threadA = new Thread(thread1);
Thread threadB = new Thread(thread1);
threadA.start();
threadB.start();
}
}
class Thread1 implements Runnable{
private Integer ticket = 100;
public void run(){
synchronized (ticket) {
while ((ticket--) >0) {
System.out.println("窗口"+Thread.currentThread().getName()+"卖票,当前票的数量为"+ticket);
}
}
}
}
计算结果: 这样就能够按照我们预定的顺序进行程序输出了。
但是我们需要注意以下问题: 第一:我们设置了synchronized代码块,那么想要访问这段代码块的线程就会被阻塞。
第二: 同样我们应该注意一个问题,我们获取到的锁是对象锁,那么如果在Thread类中存在多个synchronized方法,并且我们获取的对象的锁就是Thread类,那么只要有一个线程获取到了对象锁,那么另外的synchronized方法讲会被阻塞。
二: synchronized方法: 与上面类似,语法如下: public void synchronized test();
3. Object类中与线程锁相关的方法:
A. wait方法: 首先我们知道wait方法使当前线程释放对象锁,让其他线程可以获取对象锁进入同步代码块。并且将当前线程放入到对象等待池。
B. notify与notifyAll方法: 在当前线程中调用notify方法,则可以唤醒等待对象锁的线程执行。但是需要注意一点,如果对象等待池中存在很多线程,我们调用notifyAll方法的话,选择线程是随机的。
我们在使用的时候还应该注意一个问题,使用这些方法都必须在获取对象锁的代码块或者方法中使用。
综合例子:
public class ThreadTest {
public static Integer temp = 0;
public static void main(String[] args) throws InterruptedException{
ThreadA threadA = new ThreadA();
ThreadB threadB =new ThreadB();
threadA.start();
threadB.start();
}
}
class ThreadA extends Thread{
public void run() {
synchronized (ThreadTest.temp) {
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"输出"+i);
if(i== 3)
try {
System.out.println("线程调用wait方法");
ThreadTest.temp.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
class ThreadB extends Thread{
public void run() {
synchronized (ThreadTest.temp) {
for(int i = 0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"输出"+i);
if(i==4){
System.out.println(Thread.currentThread().getName()+"结束");
System.out.println("线程调用notify方法");
ThreadTest.temp.notify();
}
}
}
}
}
输出结果:
Thread-0输出0
Thread-0输出1
Thread-0输出2
Thread-0输出3
线程调用wait方法
Thread-1输出0
Thread-1输出1
Thread-1输出2
Thread-1输出3
Thread-1输出4
Thread-1结束
线程调用notify方法
Thread-0输出4
java线程基础知识----线程与锁的更多相关文章
- java线程基础知识----线程基础知识
不知道从什么时候开始,学习知识变成了一个短期记忆的过程,总是容易忘记自己当初学懂的知识(fuck!),不知道是自己没有经常使用还是当初理解的不够深入.今天准备再对java的线程进行一下系统的学习,希望 ...
- Java__线程---基础知识全面实战---坦克大战系列为例
今天想将自己去年自己编写的坦克大战的代码与大家分享一下,主要面向学习过java但对java运用并不是很熟悉的同学,该编程代码基本上涉及了java基础知识的各个方面,大家可以通过练习该程序对自己的jav ...
- Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量
Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量 一丶线程的理论知识 什么是线程: 1.线程是一堆指令,是操作系统调度 ...
- Java视频扩展知识 线程池的了解
Java视频扩展知识 线程池的了解 1.简单介绍: Jdk1.5之后加入了java.util.concurrent包,这个包中主要介绍java中线程以及线程池的使用.为我们在开发中处理线程的 ...
- 什么才是java的基础知识?
近日里,很多人邀请我回答各种j2ee开发的初级问题,我无一都强调java初学者要先扎实自己的基础知识,那什么才是java的基础知识?又怎么样才算掌握了java的基础知识呢?这个问题还真值得仔细思考. ...
- JAVA相关基础知识
JAVA相关基础知识 1.面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而只是选择其中的一部分, ...
- Java 多线程——基础知识
java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...
- Java多线程基础知识总结
2016-07-18 15:40:51 Java 多线程基础 1. 线程和进程 1.1 进程的概念 进程是表示资源分配的基本单位,又是调度运行的基本单位.例如,用户运行自己的程序,系统就创建一个进程, ...
- java必备基础知识(一)
学习的一点建议: 每一门语言的学习都要从基础知识开始,学习是一个过程,"万丈高楼平地起",没有一个好的地基,想必再豪华的高楼大厦终究有一天会倒塌.因此,我们学习知识也要打牢根基,厚 ...
随机推荐
- Netty使用LineBasedFrameDecoder解决TCP粘包/拆包
TCP粘包/拆包 TCP是个”流”协议,所谓流,就是没有界限的一串数据.TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TC ...
- Delphi操作XML - 冰雪傲骨
Delphi操作XMl,只要使用 NativeXml.我是用的版本是4..NativeXML的使用方法比较简单,但是功能很强大. XE2的话,要在simdesign.inc后面加上: // Delph ...
- Chrome_01_点击 Google搜索结果在新的页面打开
方法一:Ctrl + 左键 Chrome浏览器中,通过 Ctrl + 左键 ,是在新标签中打开的,通过 Shift + 左键 ,是在新窗口中打开的. 方法二: 1.登录 Google 2.进入下面的设 ...
- linux命令学习笔记(14):head 命令
head 与 tail 就像它的名字一样的浅显易懂,它是用来显示开头或结尾某个数量的文字区块,head 用来显 示档案的开头至标准输出中,而 tail 想当然尔就是看档案的结尾. .命令格式: hea ...
- android 网络编程--socket tcp/ip udp http之间的关系
网络七层由下往上分别为物理层.数据链路层.网络层.传输层.会话层.表示层和应用层,一般编程人员接触最多的就是应用层和运输层,再往下的就是所谓的媒体层了,不是我们研究的对象. 下面是应用层.运输层,网络 ...
- thinkphp中图片上传的几种好的办法
http://www.thinkphp.cn/code/701.html http://www.thinkphp.cn/code/151.html
- 【整理】如何选取后缀数组&&后缀自动机
后缀家族已知成员 后缀树 后缀数组 后缀自动机 后缀仙人掌 后缀预言 后缀Splay ? 后缀树是后缀数 ...
- VBA中的函数Timer用法
第1.40例 Timer 函数一.题目: 要求编写一段代码,运用 Timer 函数来计算本代码运行所化的时间.二.代码:Sub 示例_1_040() Dim t, i&, a t ...
- IronPython+Anthem.Net也玩 Ajax!
在 IronPython 搭建的项目中(也可以是和 C# 的混合项目,详见我前一篇 post),可以使用 Anthem.NET 来轻松实现 Ajax 功能. 下面我简单的演示一个例子:在页面上我们分别 ...
- 51nod 1301 集合异或和——异或dp
题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1301 好题!看了TJ才会. 因为是不可重集合,所以当然有前 i 个 ...