java线程同步操作实例详解

本文实例讲述了java线程同步操作。分享给大家供大家参考,具体如下:

java线程同步

public class Hello {
  public static void main(String[] args) {
    MyRun myRun0 = new MyRun();
    new Thread(myRun0, "Thread0").start();
    new Thread(myRun0, "Thread1").start();
    new Thread(myRun0, "Thread2").start();
  }
}
class MyRun implements Runnable {
  private int k = 0;
  @Override
  public void run() {
    for (int i = 0; i < 3; i++) {
      System.out.println(Thread.currentThread().getName() + "**********" + i);
      k++;
      if (k <= 3) {
        if ("Thread0".equals(Thread.currentThread().getName())) {
          try {
            Thread.sleep(100);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
        System.out.println(Thread.currentThread().getName() + "," + k);
      }
    }
  }
}

输出结果

Thread0**********0
Thread1**********0
Thread2**********0
Thread1,2
Thread2,3
Thread1**********1
Thread2**********1
Thread2**********2
Thread1**********2
Thread0,7
Thread0**********1
Thread0**********2

说明多线程在某些场景是存在问题的,有时候需要线程同步。

同步 synchronized

同步代码块,synchronized(obj){},obj是一个对象,在这里就相当于一把锁,表示一旦有进程抢到了这把锁的钥匙(就是进入了代码块),其他进程将无法进入该锁的代码块(当前代码块其他进程一定是进不来了,其他地方的代码块如果也是用了这把锁,同样进不去),只有代码块执行完,释放锁后,所有进程再重新抢钥匙。

注意,上同一把锁的代码块都会被锁住,这些代码块可能写在不同方法不同位置上。

被同步代码块包住的代码多个线程只能顺次进入。

synchronized (this) {
  k++;
  if (k <= 3) {
    if ("Thread0".equals(Thread.currentThread().getName())) {
      try {
        Thread.sleep(100);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    System.out.println(Thread.currentThread().getName() + "," + k);
  }
}

this表示当前对象,这里考虑的只是运行这个方法,不涉及其它类也不涉及这个类的其它地方需要同步问题,所以用this也是可以的。k增加和输出一个流程内只能有一个线程在访问,所以可以得到想要的输出结果

输出结果

Thread0**********0
Thread1**********0
Thread2**********0
Thread0,1
Thread0**********1
Thread2,2
Thread2**********1
Thread1,3
Thread1**********1
Thread0**********2
Thread2**********2
Thread1**********2

对方法进行同步,如果存在多线程,每个线程顺次访问该方法

注意,如果一个类里面存在多个同步方法,那么这些同步方法的锁是一个,都是当前对象,所以不同线程想同时访问同一对象的不同方法也是不行的,因为这些方法都上了同一把锁,但是钥匙只有一把,只能一个线程持有。

@Override
public synchronized void run() {
  for (int i = 0; i < 3; i++) {
    System.out.println(Thread.currentThread().getName() + "**********" + i);
    k++;
    if (k <= 3) {
      if ("Thread0".equals(Thread.currentThread().getName())) {
        try {
          Thread.sleep(100);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
      System.out.println(Thread.currentThread().getName() + "," + k);
    }
  }
}

输出结果

Thread0**********0
Thread0,1
Thread0**********1
Thread0,2
Thread0**********2
Thread0,3
Thread2**********0
Thread2**********1
Thread2**********2
Thread1**********0
Thread1**********1
Thread1**********2

死锁

public class Hello {
  public static void main(String[] args) {
    A a = new A();
    B b = new B();
    new Thread(new MyRun(a,b)).start();
    new Thread(new MyRun1(a,b)).start();
  }
}
class MyRun implements Runnable{
  private A a;
  private B b;
  public MyRun(A a, B b) {
    this.a = a;
    this.b = b;
  }
  @Override
  public void run(){
    a.say(b);
  }
}
class MyRun1 implements Runnable {
  private A a;
  private B b;
  public MyRun1(A a, B b) {
    this.a = a;
    this.b = b;
  }
  @Override
  public void run() {
    b.say(a);
  }
}
class A{
  public synchronized void say(B b){
    System.out.println("A要知道B的信息");
    b.info();
  }
  public synchronized void info(){
    System.out.println("这是A");
  }
}
class B{
  public synchronized void say(A a){
    System.out.println("B要知道A的信息");
    a.info();
  }
  public synchronized void info(){
    System.out.println("这是B");
  }
}

如果两个线程同时进入了两个say方法,就是出现死锁。

关键点在于一个对象的多个同步方法具有相同的锁,都是当前对象。也就是x线程在访问a对象的say方法过程中,y线程是无法访问a对象的info方法的,因为开锁的钥匙已经被x线程抢占了。

上面的程序,如果线程x,y同时进入了两个say方法,a对象同步方法的锁被线程x抢占,b对象同步方法的锁被线程y抢占,此时线程x无法访问b对象的同步方法,线程y无法访问a对象的同步方法。代码中恰好想要访问,所以就出现死锁了。

更多java相关内容感兴趣的读者可查看本站专题:《Java进程与线程操作技巧总结》、《Java数据结构与算法教程》、《Java操作DOM节点技巧总结》、《Java文件与目录操作技巧汇总》和《Java缓存操作技巧汇总》

希望本文所述对大家java程序设计有所帮助。

(0)

相关推荐

  • Java线程等待用法实例分析

    本文实例讲述了Java线程等待用法.分享给大家供大家参考,具体如下: 线程等待 public class Hello { public static void main(String[] args) { A a = new A(); new Thread(new MyRun(a)).start(); new Thread(new MyRun1(a)).start(); } } class MyRun implements Runnable { private A a; public MyRun(

  • Java多线程--让主线程等待所有子线程执行完毕在执行

    朋友让我帮忙写个程序从文本文档中导入数据到oracle数据库中,技术上没有什么难度,文档的格式都是固定的只要对应数据库中的字段解析就行了,关键在于性能. 数据量很大百万条记录,因此考虑到要用多线程并发执行,在写的过程中又遇到问题,我想统计所有子进程执行完毕总共的耗时,在第一个子进程创建前记录当前时间用System.currentTimeMillis()在最后一个子进程结束后记录当前时间,两次一减得到的时间差即为总共的用时,代码如下 long tStart = System.currentTime

  • java 中线程等待与通知的实现

    java 中线程等待与通知的实现 前言: 关于等待/通知,要记住的关键点是: 必须从同步环境内调用wait().notify().notifyAll()方法.线程不能调用对象上等待或通知的方法,除非它拥有那个对象的锁. wait().notify().notifyAll()都是Object的实例方法.与每个对象具有锁一样,每个对象可以有一个线程列表,他们等待来自该信号(通知).线程通过执行对象上的wait()方法获得这个等待列表.从那时候起,它不再执行任何其他指令,直到调用对象的notify()

  • Java线程中sleep和wait的区别详细介绍

    Java中的多线程是一种抢占式的机制,而不是分时机制.抢占式的机制是有多个线程处于可运行状态,但是只有一个线程在运行. 共同点: 1. 他们都是在多线程的环境下,都可以在程序的调用处阻塞指定的毫秒数,并返回. 2. wait()和sleep()都可以通过interrupt()方法 打断线程的暂停状态 ,从而使线程立刻抛出InterruptedException. 如果线程A希望立即结束线程B,则可以对线程B对应的Thread实例调用interrupt方法.如果此刻线程B正在wait/sleep/

  • Java线程关闭的3种方法

    Java线程关闭,总的来说有3种: 1.使用状态位,这个简单,就不多说了: 复制代码 代码如下: public class Task extends Thread { private volatile boolean flag= true; public void stopTask() { flag = false; } @Override public void run() { while(flag){ /* do your no-block task */ } } } 2.当线程等待某些事件

  • 图解Java线程的生命周期

    在Java中,线程有5中不同状态,分别是:新建(New).就绪(Runable).运行(Running).阻塞(Blocked)和死亡(Dead).它们之间的转换图如下: 上图有一个例外,调用yield()方法可以让当前处于运行状态的线程转入就绪状态.如果要测试某线程是否已经死亡,可以使用isAlive()方法,该方法在线程处于就绪.运行.阻塞时放回true,新建和死亡时返回false.不要试图对一个已经死亡的线程调用start()方法而重新启动,死亡就是死亡和人一样,不可能再生.还有也不要对一

  • Java多线程死锁示例

    本文实例演示了Java多线程死锁.分享给大家供大家参考,具体如下: package com.damlab.fz; public class DeadLock { public static void main(String[] args) { Resource r1 = new Resource(); Resource r2 = new Resource(); // 每个线程都拥有r1,r2两个对象 Thread myTh1 = new MyThread1(r1, r2); Thread myT

  • Java多线程实现异步调用的方法

    在JAVA平台,实现异步调用的角色有如下三个角色:调用者 提货单   真实数据 一个调用者在调用耗时操作,不能立即返回数据时,先返回一个提货单.然后在过一断时间后凭提货单来获取真正的数据. 去蛋糕店买蛋糕,不需要等蛋糕做出来(假设现做要很长时间),只需要领个提货单就可以了(去干别的事情),等到蛋糕做好了,再拿提货单取蛋糕就可以了. public class Main { public static void main(String[] args) { System.out.println("ma

  • java基本教程之java线程等待与java唤醒线程 java多线程教程

    本章,会对线程等待/唤醒方法进行介绍.涉及到的内容包括:1. wait(), notify(), notifyAll()等方法介绍2. wait()和notify()3. wait(long timeout)和notify()4. wait() 和 notifyAll()5. 为什么notify(), wait()等函数定义在Object中,而不是Thread中 wait(), notify(), notifyAll()等方法介绍在Object.java中,定义了wait(), notify()

  • Java线程同步方法实例总结

    本文实例讲述了Java线程同步方法.分享给大家供大家参考,具体如下: 1. Semaphore 1.1 二进制Semaphore Semaphore算是比较高级点的线程同步工具了,在许多其他语言里也有类似的实现.Semaphore有一个最大的好处就是在初始化时,可以显式的控制并发数.其内部维护这一个c计数器,当计数器小于等于0时,是不允许其他线程访问并发区域的,反之则可以,因此,若将并发数设置为1,则可以确保单一线程同步.下面的例子模拟多线程打印,每个线程提交打印申请,然后执行打印,最后宣布打印

  • 详解java中的互斥锁信号量和多线程等待机制

    互斥锁和信号量都是操作系统中为并发编程设计基本概念,互斥锁和信号量的概念上的不同在于,对于同一个资源,互斥锁只有0和1 的概念,而信号量不止于此.也就是说,信号量可以使资源同时被多个线程访问,而互斥锁同时只能被一个线程访问 互斥锁在java中的实现就是 ReetranLock , 在访问一个同步资源时,它的对象需要通过方法 tryLock() 获得这个锁,如果失败,返回 false,成功返回true.根据返回的信息来判断是否要访问这个被同步的资源.看下面的例子 public class Reen

随机推荐