不少同学在学习Java中的多线程这一章时,都会觉得脑子很乱,觉得这一章的知识点太难以理解。特别是对于其中线程同步(synchronized)更是迷茫。本文试图以浅显的例子来跟大家共同分享学习心得。
先看一个例子
package com.chinasofti.thread;
publicclass MyThread implements Runnable{
privateinta = 1;
publicsynchronizedvoid f1(){
System.out.println("a = " + a);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("a = " + a);
}
publicvoid f2(){
a++;
}
publicvoid run() {
f1();
}
publicstaticvoid main(String[] args) {
MyThread myThread = newMyThread();
Thread t1 = newThread(myThread);
t1.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
myThread.f2();
}
}
例子说明:我们自定义了一个MyThread类,该类实现了java.lang.Runnable接口。类中包含一个静态私有变量a=1;提供了一个同步方法f1,该方法的作用是先打印a,然后执行该方法的线程休眠1000毫秒,再次打印a;提供了一个非同步方法f2,该方法作用是使a自加1;实现java.lang.Runnable接口的run方法,该方法执行f1()。
程序启动时,首先启动主线程执行main方法。在main方法中,先new一个MyThread类对象myThread,再利用该对象创建一条线程t1,调用其start()方法启动线程,主线程休眠100毫秒的作用是使得t1在主线程休眠期间得到CPU执行权,执行到f1()方法中的Thread.sleep(1000)处。在t1线程休眠1000毫秒时,主线程继续执行MyThread.f2()。该测试程序的最终结果是打印a=1 a=2。也就是说在t1线程执行同步方法f1并休眠1000毫秒的空当里,主线程执行了myThread对象的非同步方法f2(),修改了a的值。t1线程从休眠中恢复过来再次打印a的值已经变成了2。
也许有同学看到这里就有疑问了:“我们不是说synchronized的意思是获得对象锁吗?那么t1线程执行了同步方法f1(),那就应该获得myThread对象的对象锁啊,怎么在它休眠期间另一条线程主线程也能够执行myThread对象的f2()方法呢?难道是因为t1线程休眠了之后就释放掉对象锁了吗?”
对于这个问题的解释是这样,t1线程执行run()方法,run()方法调用同步方法f1(),则此时t1线程拥有了myThread这个对象的对象锁,接下来执行Thread.sleep(long miliseconds)这个方法,则线程(即t1)进入休眠状态,但是Thread.sleep(long miliseconds)的执行不会导致线程释放掉对象锁。而main线程之所以能够在t1线程休眠之后继续执行myThread.f2(),是因为f2()并不是同步方法。我们通常说“获得对象锁”,实际上更确切直白的含义是“独占该对象的同步方法和同步代码块”。但是对于非同步方法,对象锁是不起作用的。
我们可以将例子做如下改动:将f2()修改为同步方法,其他不变。大家有兴趣试一下会发现此时的程序执行结果变成了打印a=1 a=1。因为此时f2()为同步方法,t1线程在休眠期间并没有释放对象锁,即此时t1线程“独占myThread对象的f1(),f2()方法”。因此此时主线程不可能执行myThread.f2()。只有当t1线程执行完了f1()方法之后,即两次打印a=1 a=1,释放掉对象锁,此时主线程才能继续执行myThread的同步方法f2()。
很多同学在理解“同步”这个概念时错误地将其理解成为“并行”,从而得到一些混乱的结论,最后变得越来越茫然。而通过上面的例子我们可以看到,其实线程中“同步”的概念更接近于“串行”。即“同一时刻只能有一条线程拥有一个对象的对象锁,在该线程独占该对象的同步方法和同步代码块时,其他线程不能访问该对象的同步方法和同步代码块”。而synchronized关键字的作用是声明同步方法或者同步代码块,执行到这儿的线程可以告诉其他线程说:“嘿,现在这个对象的同步方法和代码块我占了,你们先等着别抢,我用完了你们才能接着用!”。
分享到:
相关推荐
### Java同步机制浅谈 #### synchronized关键字的作用及应用 在Java多线程环境中,`synchronized`关键字扮演着至关重要的角色。它可以帮助开发者确保多线程环境下的数据一致性,防止因并发访问导致的数据错误。本...
在Java中,synchronized关键字是用来实现线程同步的,它可以保证在多线程环境中,某个方法或代码块只能被一个线程访问。今天,我们来探讨synchronized方法对非synchronized方法的影响。 首先,我们来看一个例子。...
4. synchronized关键字:用于同步控制,保证多线程环境下对共享资源的访问有序性。它可以修饰方法或代码块,确保同一时间只有一个线程可以执行特定代码。 5. volatile关键字:用于确保多线程环境下的可见性和有序性...
1. **synchronized关键字**:可以在方法或者代码块上使用`synchronized`关键字来确保同一时间只有一个线程可以访问被同步的代码区域。 2. **Lock接口**:Java提供了`java.util.concurrent.locks.Lock`接口,允许更...
Java提供了多种同步机制,其中最常见的是`synchronized`关键字,用于防止多个线程同时访问同一代码段: 1. **实例方法同步**:锁定在实例对象上,一个实例的同步方法同一时间只能被一个线程执行。 2. **静态方法...
浅谈Java多线程实现及同步互斥通讯 多线程实现方式: Java中的多线程实现方式共有两种:通过继承Thread类和通过实现Runnable接口。下面我们来详细了解这两种方式: 1. 通过继承Thread类来实现多线程: 通过继承...
1. `@synchronized` 是Objective-C中的一个关键字,它提供了一种简单的方式来实现线程同步。使用 `@synchronized` 关键字时,你需要提供一个对象作为锁的标识,确保只有当这个对象相同的锁被持有时,代码块才会被...
为了保证数据一致性,当多个线程可能访问共享资源时,需要使用同步机制,如`synchronized`关键字或`java.util.concurrent`包中的工具类。 以下是一个简单的示例,展示了两个线程交替打印"A"和"B": ```java public...
print()方法中使用synchronized关键字来实现同步,使用wait()和notify()方法来实现线程之间的通信。 在print()方法中,我们使用while循环来实现打印10个数。当i小于10时,打印当前线程的名称和数字,然后执行notify...
《浅谈Windows中的多线程编程》文档可能以更通俗易懂的方式探讨Windows下的线程概念。它可能涵盖线程的生命周期、线程间交互的基本原理,以及处理线程安全问题的策略。文档可能会针对初学者,解释线程在日常软件开发...
在上面的代码中,我们首先创建了两个线程对象t1和t2,然后启动了t1线程,然后使用synchronized关键字来同步线程,最后使用notify方法来唤醒t1线程,最后启动t2线程。 join方法的应用场景 join方法的应用场景非常...
在Java中,`synchronized`关键字用于控制并发访问,保证同一时刻只有一个线程能够执行特定的代码块,以防止数据的不一致性。 首先,我们要理解Java中的自动装箱机制。当我们将基本类型`boolean`赋值给`Boolean`对象...
- **线程安全的代价**:由于Hashtable是线程安全的,它的内部实现使用了synchronized关键字,这可能导致在多线程环境下的性能问题。 - **无泛型支持**:Hashtable属于旧版集合框架,不支持泛型,这意味着在使用时...
AtomicInteger是Java并发包java.util.concurrent.atomic中的一个类,提供了对单个整型变量进行原子操作的能力,避免了在多线程环境下使用synchronized关键字的复杂性和开销。本文将深入浅出地探讨AtomicInteger的...
- **阻塞队列**:在实际开发中,Java的`java.util.concurrent`包提供了阻塞队列(如`BlockingQueue`),它内置了线程同步机制,可以更方便地解决生产者与消费者问题,简化代码。 - **信号量**:`Semaphore`类可以...
7. **多线程**:介绍并发编程的基础,如何创建和管理线程,同步机制(synchronized关键字和wait/notify机制)以及线程池的使用。 8. **枚举与注解**:讲解枚举类型及其应用,以及注解的使用,包括自定义注解和元...
4. **线程同步与通信**:使用`synchronized`关键字、`wait()`、`notify()`或`Condition`等机制,确保线程间的同步,防止死锁和资源竞争。 5. **优化任务执行**:尽量减少线程阻塞的时间,例如,避免长时间的IO操作...
同步可以通过关键字`synchronized`实现,它阻止多个线程同时访问同一块代码,确保资源的独占使用。 同步容器,如`Vector`和`Hashtable`,提供了线程安全的访问,但它们通常效率较低,因为对整个容器的访问都是锁定...
- 在Java中,通过`synchronized`关键字实现线程同步,确保连接的并发安全。 2. **多数据库服务器与多用户支持** - 设计单例模式的连接池管理类,根据配置文件中的数据库信息动态创建和管理不同的连接池。 3. **...