Java多线程学习篇(二)synchronized

synchronized 有二种修饰方法:
  1. 修饰一个方法

    synchronized public void runTest{
        /**/
    }
  2. 修饰一个代码块
    public void runTest{
        synchronized( /*某一对象或某一类*/ ){
            /* 代码块 */
        }
    }
synchronized 的作用范围分为修饰一个类和修饰一共对象当修饰一个对象时,不同线程的同一对象调用相同代码会发生堵塞当修饰一个类时,不同线程的同一类调用相同代码会发生堵塞修饰静态方法相当于修饰类

定义一个类(用于验证 synchronized 的作用范围)

public class Test implements Runnable {

    public static int Count = 0;

    @Override
    public void run() {
        runTest();
    }

    public void runTest() {
        for (int i = 0; i < 5; ++i) {
            Count++;
            System.out.println(Thread.currentThread().getName() + " " + Count);
        }
    }
}

当 synchronized 修饰一个方法时

  1. 若方法为非静态方法,作用的范围是一个对象

    不同线程的同一对象调用该方法时会发生堵塞

    //调用相同的对象synchronized public void runTest() {  // 修饰非静态的方法
        for (int i = 0; i < 5; ++i) {
            Count++;
            System.out.println(Thread.currentThread().getName() + " " + Count);
        }
    }

    通过以下代码调用

    Test test = new Test();
    Thread thread_one = new Thread( test, "Thread_ONE" );
    Thread thread_two = new Thread( test, "Thread_Two" );
    thread_one.start();
    thread_two.start();

    结果是

    Thread_ONE 1
    Thread_ONE 2
    Thread_ONE 3
    Thread_ONE 4
    Thread_ONE 5
    Thread_Two 6
    Thread_Two 7
    Thread_Two 8
    Thread_Two 9
    Thread_Two 10

    由于该调用是二个thread任务中的对象是同一个test,第一个thread任务运行时,会将第二个任务堵塞

    若对象不是同一个,则不会发生堵塞

    //调用二个不同的对象
    Thread thread_one = new Thread(new Test(), "Thread_ONE");
    Thread thread_two = new Thread(new Test(), "Thread_Two");
    thread_one.start();
    thread_two.start();

    结果是

    Thread_Two 2
    Thread_ONE 1
    Thread_Two 3
    Thread_ONE 4
    Thread_Two 5
    Thread_ONE 6
    Thread_Two 7
    Thread_ONE 8
    Thread_Two 9
    Thread_ONE 10
  2. 当修饰的方法为静态的方法时,作用的范围是一个类,而非一个对象。

    不同线程的相同类调用该方法时都会发生堵塞

    //调用相同的对象
    Test test = new Test();
    Thread thread_one = new Thread( test, "Thread_ONE" );
    Thread thread_two = new Thread( test, "Thread_Two" );
    thread_one.start();
    thread_two.start();
    
    //调用二个不同的对象
    Thread thread_one = new Thread(new Test(), "Thread_ONE");
    Thread thread_two = new Thread(new Test(), "Thread_Two");
    thread_one.start();
    thread_two.start();

    结果都为

    Thread_ONE 1
    Thread_ONE 2
    Thread_ONE 3
    Thread_ONE 4
    Thread_ONE 5
    Thread_Two 6
    Thread_Two 7
    Thread_Two 8
    Thread_Two 9
    Thread_Two 10

当 synchronized 修饰一个代码块时,作用的范围看括号内的内容。若括号内为对象,则范围是一个对象;若括号内为类,则范围是一个类

  1. 若括号内为对象,则范围是一个对象,效果和 synchronized 修饰非静态方法一样

    public void runTest() {
        synchronized (this) { // 括号内为一个对象
            for (int i = 0; i < 5; ++i) {
                Count++;
                System.out.println(Thread.currentThread().getName() + " " + Count);
            }
        }
    }

    效果

    //调用相同的对象
    Test test = new Test();
    Thread thread_one = new Thread( test, "Thread_ONE" );
    Thread thread_two = new Thread( test, "Thread_Two" );
    thread_one.start();
    thread_two.start();
    //发生类堵塞
    //Thread_ONE 1
    //Thread_ONE 2
    //Thread_ONE 3
    //Thread_ONE 4
    //Thread_ONE 5
    //Thread_Two 6
    //Thread_Two 7
    //Thread_Two 8
    //Thread_Two 9
    //Thread_Two 10
    
    //调用二个不同的对象
    Thread thread_one = new Thread(new Test(), "Thread_ONE");
    Thread thread_two = new Thread(new Test(), "Thread_Two");
    thread_one.start();
    thread_two.start();
    // 没有发生堵塞
    //Thread_Two 2
    //Thread_ONE 1
    //Thread_Two 3
    //Thread_ONE 4
    //Thread_Two 5
    //Thread_ONE 6
    //Thread_Two 7
    //Thread_ONE 8
    //Thread_Two 9
    //Thread_ONE 10
  2. 若括号内为类,则范围是一个对象,效果和 synchronized 修饰静态方法一样
    public [static] void runTest() {
        synchronized (Test.class) { // 括号内为一个类
            for (int i = 0; i < 5; ++i) {
                Count++;
                System.out.println(Thread.currentThread().getName() + " " + Count);
            }
        }
    }

    二种调用都发生堵塞

    Thread_ONE 1
    Thread_ONE 2
    Thread_ONE 3
    Thread_ONE 4
    Thread_ONE 5
    Thread_Two 6
    Thread_Two 7
    Thread_Two 8
    Thread_Two 9
    Thread_Two 10

参考:http://tutorials.jenkov.com/java-concurrency/synchronized.html

原文地址:https://www.cnblogs.com/lkcc/p/8178963.html

时间: 2024-10-29 21:19:27

Java多线程学习篇(二)synchronized的相关文章

Java多线程学习篇(三)Lock

Lock 是Java多线程的一个同步机制,用来控制线程对共享资源的访问.线程在执行同步方法或者代码块之前必须先获得一个锁. Lock 的 lock() 和 unlock() 方法; lock():获得一个锁,如果锁不可用,则当前线程将因线程调度目的而被禁用,并在获得锁之前处于休眠状态. unlock():释放掉获得的锁. Lock的作用范围: 若 Lock 是静态的,则作用范围是整个类. public class Test { public static void main(String[] a

Java多线程学习(二)

一.定义产生返回值的任务 在上一篇文的介绍中,我们知道了定义任务通常的方法是定义一个实现Runnable接口的类,这个类被我们成为任务.然而也很容易注意到,任务的最重要的一个方法就是run( )方法,而run( )方法是没有返回值的,也就是说我们之前定义的任务不返回任何值. 如果想要定义一个有返回值的任务,则需要编写一个实现Callable接口的类.Callable是一种具有类型参数的泛型,他的类型参数表示的是call( )方法的返回值类型. 示例如下: 1 import java.util.c

java多线程学习-同步(synchronized)

(示例都是网上视频的) 假如两个线程同时调用一个方法输出字符串 public class SynchronizedTest extends Thread { public static void main(String[] args) { final SynchronizedTest st = new SynchronizedTest(); new Thread(new Runnable() { public void run() { while(true){ try { Thread.slee

java多线程学习(二)——线程的创建

一.java创建线程的两个方法 1.从java.lang.Thread类派生出一个新的线程类,重载它的run()方法 2.实现Runnable接口,重载Runnable接口中的run()方法. 使用Thread类来创建线程和创建普通类的对象的操作是一样的,线程是Thread类或者其子类的实例对象. 二.java提供的两种创建线程的区别 java中类是单继承的,当定义一个新的线程类的时候,它只能扩展一个外部类,那么当创建的线程是继承自Thread类来实现的,那么此线程类无法再扩展其他类,无法实现复

Java多线程学习篇(一)

多线程的目的:更高效的利用CPU 创建任务和线程 一个任务类必须实现Runnable接口,任务必须从线程运行. 实现Runnable接口 // 任务类 public class TaskClass implements Runnable { public TaskClass(){ } @Override // 实现Runnable中的run方法 public void run() { // 将要运行的任务 } } 创建并运行任务 public class Client { public void

JAVA Web学习篇--Servlet

Servlet由来 做过BS项目的人都知道,浏览器可以依据HTML静态标记语言来显示各式各样的网页.可是假设我们须要在网页上完毕一些业务逻辑:比方登陆验证.或者说网页显示的内容在server的数据库中.假设是这样,除了负责显示的HTML标记之外,必须还要有完毕这些业务功能的代码存在.这样的网页我们就叫做动态网页. 对于静态网页而言,server上存在的是一个个纯HTML文件.当client浏览器发出HTTP请求时,server能够依据请求的URL找到相应的HTML文件,并将HTML代码返回给cl

[转]Java多线程学习(总结很详细!!!)

Java多线程学习(总结很详细!!!) 此文只能说是java多线程的一个入门,其实Java里头线程完全可以写一本书了,但是如果最基本的你都学掌握好,又怎么能更上一个台阶呢? 本文主要讲java中多线程的使用方法.线程同步.线程数据传递.线程状态及相应的线程函数用法.概述等.首先让我们来了解下在操作系统中进程和线程的区别: 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程.(进程是资源分配的最小单位) 线程:同一类线程共享代码和数据空间,

java多线程学习(3)

1)竞争条件 在实际的多线程应用中,通常会有两个或多个线程需要对共同的对象进行共享访问,如果两个线程访问相同的对象,而且每一个都调用了一个会改变对象状态的方法, 那么,线程就会相互倾轧.根据各个线程访问数据的不同顺序,可能会产生腐蚀现象.这种情况通常称为竞争条件. 2)同步 为了多个线程对共享数据的腐蚀,就需要对数据的存取实现同步:常用的同步方法有3种: 1.Reenlock 用Reenlock保护代码块的基本机构如下: 1 Lock myLock=new ReenLock; 2 3 myLoc

黑马程序员之Java多线程学习

android培训  java培训 期待与您交流! 这一篇文章主要关于java多线程,主要还是以例子来驱动的.因为讲解多线程的书籍和文章已经很多了,所以我也不好意思多说,呵呵.大家可以去参考一些那些书籍.我这个文章主要关于实际的一些问题.同时也算是我以后复习的资料吧,.呵呵大家多多指教. 同时希望多结交一些技术上的朋友.谢谢. -------------------------------------------------------------------------------------