java线程之线程同步

关于线程的安全问题,这里举一个很简单的银行取钱的问题:

  • 用户输入账号,密码,系统判断是否匹配
  • 用户输入取钱金额
  • 系统判断取钱金额是否合理,是否大于余额数
  • 如果取钱金额小于等于余额,取钱成功,大于则失败

当两个用户使用同一个账号取钱时,相当于两个线程并发取钱,则可能出现错误。

出现错误的原因是因为run()方法不具有同步安全性。为了解决这个问题,java多线程支持引入同步监视器,使用同步监视器的格式如下:

sysnchronized(boj){

..........

}

其运行逻辑是:加锁>修改>释放锁

synchronized关键字可以修饰方法,代码块,不能修饰构造器,成员变量

如下几种情况会释放同步监视器

  1. 当前执行线程的同步方法或者同步代码块执行结束
  2. 当前执行线程的同步方法或者同步代码遇到break,return终止了该方法或者代码块
  3. 当前执行线程的同步方法或者同步代码的程序中执行了同步监视器对象的wait()方法

如下几种情况不会释放同步监视器

  1. 线程执行同步方法或者同步代码块时,程序调用了Thread.sleep(),Thread.yield()方法
  2. 线程执行代码块时,其他线程执行该线程的suspend()方法将该线程挂起

这里放一个银行取钱的小例子:

package com.tc.test;

public class Acount {
    private String accountNo;
    private double balance;

    public Acount(String accountNo, double balance) {
        super();
        this.accountNo = accountNo;
        this.balance = balance;
    }

    public String getAccountNo() {
        return accountNo;
    }
    public void setAccountNo(String accountNo) {
        this.accountNo = accountNo;
    }
    public double getBalance() {
        return balance;
    }
//    public void setBalance(double balance) {
//        this.balance = balance;
//    }
    public synchronized void draw(double drawAmount){
        if( balance > drawAmount ){
            System.out.println(Thread.currentThread().getName()
                    +"取钱成功"+drawAmount);
            try{
                Thread.sleep(1);
            } catch(InterruptedException e){
                e.printStackTrace();
             }
            //修改余额
            balance-=drawAmount;
            System.out.println("余额为:"+balance);
        }else{
            System.out.println("取钱失败,余额不足!!!");
        }
    }

}
package com.tc.test;

public class DrawThread extends Thread {
    private Acount account;
    private double drawAmount;
    public DrawThread(String name , Acount account, double drawAmount) {
        super(name);
        this.account = account;
        this.drawAmount = drawAmount;
    }
    public void run(){
        account.draw(drawAmount);
    }

}
package com.tc.test;

public class DrawTest {

    public static void main(String[] args) {
            Acount ac=new Acount("123",1000);
            new DrawThread("第一个",ac,800).start();
            new DrawThread("第二个",ac,800).start();
    }

}

同步锁

从jdk1.5开始,java提供了一种功能更强大的线程同步机制————通过显示定义同步锁对象来实现同步,在这种机制下,同步锁由Lock对象充当。

Lock是控制对个线程对共享资源的进行访问的工具,通常锁提供了对共享资源的独占访问,每次只能有一个线程对lock加锁,线程在访问共享资源之前必须先获得Lock对象

java8新增了新型的StampedLock类,为读写提供了三种锁模式:Writing,ReadOptimistic,Reading 。

死锁

当两个线程互相等待对方释放同步监视器时就会发生死锁,java虚拟机并没有检测,也没有采取措施来处理死锁,一旦出现死锁,整个程序不会发生任何异常,也不会有任何提示,只是所有线程处于阻塞状态。

时间: 2024-12-31 03:35:56

java线程之线程同步的相关文章

java进阶07 线程的让步与阻塞与同步

前面介绍了线程的一些基本知识,现在来说下线程的让步,阻塞,和同步 先说说让步 所谓让步,就是让调用者的线程暂停,让其他线程重新竞争CPU,包括调用者. 先看看代码 package Thread; public class ThreadYield { public static void main(String[] args){ MyThread5 rthread=new MyThread5(); Thread thread1=new Thread(rthread); Thread thread2

Java线程:线程的同步与锁

一.同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 例如:两个线程ThreadA.ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据. public class Foo {     private int x = 100; public int getX() {         return x;     } public int fix(int y) {         x = x - y;         return x;     } }

浅谈利用同步机制解决Java中的线程安全问题

我们知道大多数程序都不会是单线程程序,单线程程序的功能非常有限,我们假设一下所有的程序都是单线程程序,那么会带来怎样的结果呢?假如淘宝是单线程程序,一直都只能一个一个用户去访问,你要在网上买东西还得等着前面千百万人挑选购买,最后心仪的商品下架或者售空......假如饿了吗是单线程程序,那么一个用户得等前面全国千万个用户点完之后才能进行点餐,那饿了吗就该倒闭了不是吗?以上两个简单的例子,就说明一个程序能进行多线程并发访问的重要性,今天就让我们去了解一下Java中多线程并发访问这个方向吧. **第一

Java笔记六.线程同步、线程死锁

线程同步.线程死锁 在上一篇文章中,有一个模拟售卖火车票系统,在卖车票的程序代码中,极有可能碰到一种意外,就是同一张票号被打印两次多次,也可能出现打印出0甚至负数的票号.具体表现为:假设tickets的值为1的时候,线程1刚执行完if(tickets>0)这行代码,正准备执行下面的代码,就在这时,操作系统将CPU切换到了线程2上执行,此时tickets的值仍为1,线程2执行完上面两行代码,tickets的值变为0后,CPU又切回到了线程1上执行,线程1不会再执行if(tickets>0)这行代

Java中处理线程同步

引自:http://blog.csdn.net/aaa1117a8w5s6d/article/details/8295527和http://m.blog.csdn.net/blog/undoner/12849661 静态变量:线程非安全. 静态变量即类变量,位于方法区,为所有对象共享,共享一份内存,一旦静态变量被修改,其他对象均对修改可见,故线程非安全. 实例变量:单例模式(只有一个对象实例存在)线程非安全,非单例线程安全. 实例变量为对象实例私有,在虚拟机的堆中分配,若在系统中只存在一个此对象

java虚拟机之线程同步

线程同步 java 编程语言其中一个优点就是提供了语言层面的多线程支持.多线程支持主要是围绕synchronization来展开的:在多个线程之间协调数据访问.java用来实现同步的机制我们称作为monitor.本文将介绍monitor以及java虚拟机是如何使用monitor的——有指令集支持的数据加锁与解锁. monitor java监视器(monitor)支持两种类型的线程同步,互斥与协作,互斥:java虚拟机通过object 锁来实现互斥,允许多个线程在共享数据上不相互干扰的work:协

java多线程之线程的同步与锁定(转)

一.同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 例如:两个线程ThreadA.ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据. publicclass Foo { privateint x = 100; publicint getX() { return x;     } publicint fix(int y) {         x = x - y; return x;     } } publicclass MyRunnable i

java多线程之 ---- 线程同步

java多线程之线程同步 线程同步 定义:同步是指在同一时间段内只能运行一个线程. 分类:同步方法.同步块. 作用:安全解决共享问题. 同步块: 语法: synchronized (同步对象) { 需要同步的代码; } 例子: public class ThreadDemo implements Runnable{ private int ticket = 5; public void run(){ for(int i=1;i<=5;i++){ synchronized (this){ if(t

Java并发原语——线程、互斥与同步

本文将介绍: Java线程基本操作(创建.等待等) Java线程同步原语(同步.互斥) 如果你对以上话题已了如指掌,请止步. Java线程基本操作 Java的线程API以java.lang.Thread类提供,线程的基本操作被封装为为Thread类的方法,其中常用的方法是:   方法 说明 void start() 启动线程 void join() 等待线程结束 创建(启动)线程 Java中,创建线程的过程分为两步: 创建可执行(Runnable)的线程对象: 调用它的start()方法: 可执

java学习之协调同步的线程

当一个线程使用的同步方法中用到某个变量,而此变量有需要其他线程修改后才能符合本线程的需要, 那么可以在同步方法中使用wait(),wait方法可以中断线程的执行,使本线程等待,暂时让出CPU的使用权,并允许其他线程使用这个同步方法. 其他线程如果在使用这个同步方法时,不许需要等待,那么它使用这个同步方法.其他线程如果再使用这个同步方法是不需要等待,那么它使用完 这个同步方法的同时,应当用notifyAll()方法通知所有由于使用这个同步方法而处于等待的线程结束等待.曾中断的线程就会从刚才的中断处