进行多线程编程,同步控制是非常重要的,而同步控制就涉及到了锁。
对代码进行同步控制我们可以选择同步方法,也可以选择同步块,这两种方式各有优缺点,至于具体选择什么方式,就见仁见智了,同步块不仅可以更加精确的控制对象锁,也就是控制锁的作用域,何谓锁的作用域?锁的作用域就是从锁被获取到其被释放的时间。而且可以选择要获取哪个对象的对象锁。但是如果在使用同步块机制时,如果使用过多的锁也会容易引起死锁问题,同时获取和释放所也有代价,而同步方法,它们所拥有的锁就是该方法所属的类的对象锁,换句话说,也就是this对象,而且锁的作用域也是整个方法,这可能导致其锁的作用域可能太大,也有可能引起死锁,同时因为可能包含了不需要进行同步的代码块在内,也会降低程序的运行效率。而不管是同步方法还是同步块,我们都不应该在他们的代码块内包含无限循环,如果代码内部要是有了无限循环,那么这个同步方法或者同步块在获取锁以后因为代码会一直不停的循环着运行下去,也就没有机会释放它所获取的锁,而其它等待这把锁的线程就永远无法获取这把锁,这就造成了一种死锁现象。
详细解说一下同步方法的锁,同步方法分为静态同步方法与非静态同步方法。
所有的非静态同步方法用的都是同一把锁——实例对象本身,也就是说如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁,可是别的实例对象的非静态同步方法因为跟该实例对象的非静态同步方法用的是不同的锁,所以毋须等待该实例对象已获取锁的非静态同步方法释放锁就可以获取他们自己的锁。
而所有的静态同步方法用的也是同一把锁——类对象本身,这两把锁是两个不同的对象,所以静态同步方法与非静态同步方法之间是不会有竞态条件的。但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,而不管是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同步方法之间,只要它们同一个类的实例对象!
而对于同步块,由于其锁是可以选择的,所以只有使用同一把锁的同步块之间才有着竞态条件,这就得具体情况具体分析了,但这里有个需要注意的地方,同步块的锁是可以选择的,但是不是可以任意选择的!!!!这里必须要注意一个物理对象和一个引用对象的实例变量之间的区别!使用一个引用对象的实例变量作为锁并不是一个好的选择,因为同步块在执行过程中可能会改变它的值,其中就包括将其设置为null,而对一个null对象加锁会产生异常,并且对不同的对象加锁也违背了同步的初衷!这看起来是很清楚的,但是一个经常发生的错误就是选用了错误的锁对象,因此必须注意:同步是基于实际对象而不是对象引用的!多个变量可以引用同一个对象,变量也可以改变其值从而指向其他的对象,因此,当选择一个对象锁时,我们要根据实际对象而不是其引用来考虑!作为一个原则,不要选择一个可能会在锁的作用域中改变值的实例变量作为锁对象!!!!
Java线程:线程的同步与锁
private int x = 100;
public int getX() {
return x;
}
public int fix(int y) {
x = x - y;
return x;
}
}
private Foo foo = new Foo();
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
Thread ta = new Thread(r, "Thread-A");
Thread tb = new Thread(r, "Thread-B");
ta.start();
tb.start();
}
public void run() {
for (int i = 0; i < 3; i++) {
this.fix(30);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " : 当前foo对象的x值= " + foo.getX());
}
}
public int fix(int y) {
return foo.fix(y);
}
}
Thread-B : 当前foo对象的x值= 40
Thread-B : 当前foo对象的x值= -20
Thread-A : 当前foo对象的x值= -50
Thread-A : 当前foo对象的x值= -80
Thread-B : 当前foo对象的x值= -80
Process finished with exit code 0
6)、线程睡眠时,它所持的任何锁都不会释放。
synchronized (this) {
x = x - y;
}
return x;
}
return x++;
}
synchronized (this) {
return x;
}
}
public static int setName(String name){
synchronized(Xxx.class){
Xxx.name = name;
}
}
private List nameList = Collections.synchronizedList(new LinkedList());
public void add(String name) {
nameList.add(name);
}
public String removeFirst() {
if (nameList.size() > 0) {
return (String) nameList.remove(0);
} else {
return null;
}
}
}
public static void main(String[] args) {
final NameList nl = new NameList();
nl.add("aaa");
class NameDropper extends Thread{
public void run(){
String name = nl.removeFirst();
System.out.println(name);
}
}
Thread t1 = new NameDropper();
Thread t2 = new NameDropper();
t1.start();
t2.start();
}
}
private List nameList = Collections.synchronizedList(new LinkedList());
public synchronized void add(String name) {
nameList.add(name);
}
public synchronized String removeFirst() {
if (nameList.size() > 0) {
return (String) nameList.remove(0);
} else {
return null;
}
}
}
private static class Resource {
public int value;
}
private Resource resourceA = new Resource();
private Resource resourceB = new Resource();
public int read() {
synchronized (resourceA) {
synchronized (resourceB) {
return resourceB.value + resourceA.value;
}
}
}
public void write(int a, int b) {
synchronized (resourceB) {
synchronized (resourceA) {
resourceA.value = a;
resourceB.value = b;
}
}
}
}
- package com.etrip.concurrent.executor;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Map.Entry;
- import java.util.Set;
- /**
- * 非静态同步方法,静态同步方法,同步语句块的使用
- *
- *
- * 进行多线程编程,同步控制是非常重要的,而同步控制就涉及到了锁。
- 对代码进行同步控制我们可以选择同步方法,也可以选择同步块,这两种方式各有优缺点,至于具体选择什么方式,就见仁见智了,同步块不仅可以更加精确的控制对象锁,也就是控制锁的作用域,何谓锁的作用域?锁的作用域就是从锁被获取到其被释放的时间。而且可以选择要获取哪个对象的对象锁。但是如果在使用同步块机制时,如果使用过多的锁也会容易引起死锁问题,同时获取和释放所也有代价,而同步方法,它们所拥有的锁就是该方法所属的类的对象锁,换句话说,也就是this对象,而且锁的作用域也是整个方法,这可能导致其锁的作用域可能太大,也有可能引起死锁,同时因为可能包含了不需要进行同步的代码块在内,也会降低程序的运行效率。而不管是同步方法还是同步块,我们都不应该在他们的代码块内包含无限循环,如果代码内部要是有了无限循环,那么这个同步方法或者同步块在获取锁以后因为代码会一直不停的循环着运行下去,也就没有机会释放它所获取的锁,而其它等待这把锁的线程就永远无法获取这把锁,这就造成了一种死锁现象。
- *
- * @author longgangbai
- */
- public class StaticInstanceLock {
- private int count;
- private static StaticInstanceLock instance=null;
- private StaticInstanceLock(){
- }
- /**
- * 静态方法的锁
- *
- * @return
- */
- public static synchronized StaticInstanceLock getInstance(){
- if(instance==null){
- instance=new StaticInstanceLock();
- }
- return instance;
- }
- /**
- * 非静态方法的锁
- * @return
- */
- public synchronized int getCount(){
- return count;
- }
- public synchronized void setCount(int count){
- this.count=count;
- }
- /**
- * 同步语句块的使用
- *
- */
- public void synmethod(){
- //HashMap为非安全性Map
- HashMap<String,String> hashmap = new HashMap<String,String>();
- hashmap.put("ZH","中国");
- hashmap.put("EN","英国");
- hashmap.put("AM","美国");
- hashmap.put("FR","法国");
- //创建一个同步的对象Map
- Map<String,String> m = Collections.synchronizedMap(hashmap);
- Set<String> s = m.keySet(); // Needn't be in synchronized block
- //这里同步的对象均为需要使用同步的对象如Map而非Set
- synchronized(m) { // Synchronizing on m, not s!
- Iterator<String> i = s.iterator(); // Must be in synchronized block
- while (i.hasNext()){
- foo(i.next());
- }
- }
- }
- public void foo(String entry){
- System.out.println("StaticInstanceLock ="+entry);
- }
- public static void main(String[] args) {
- StaticInstanceLock instance=StaticInstanceLock.getInstance();
- instance.setCount(7);
- int count = instance.getCount();
- instance.synmethod();
- }
- }
相关推荐
- **对象锁**:如果`synchronized`修饰非静态方法或者同步语句块中的对象引用是实例引用,那么锁定的是该实例对象。例如: ```java public class MyObject { public synchronized void method() { // ... } }...
在Java中,使用synchronized关键字可以作用在方法上,从而保证了访问同一个对象的同一个方法的线程同步。例如: public synchronized void testFun(String str){ for(int i=0;i;i++){ System.out.println(str+",...
10. **Main方法的终结**:在Java中,main方法可以正常结束,当程序执行完main方法内的所有语句,或者遇到return语句时,main方法会结束,程序也随之终止。如果需要在main方法结束后执行某些清理工作,可以使用...
- 使用wait()时,必须在同步代码块(由synchronized修饰的方法或代码块)中调用,因为只有持有锁的线程才能调用wait()。 - 恢复执行的线程会从wait()调用后的下一条语句开始,因此通常在循环中调用wait(),以确保...
因此,不能将main方法改为非静态。 5. **main方法是否可重载**:可以,一个Java类可以有多个main方法,只要它们的参数列表不同即可。但是,通常只会在主类中定义一个用于程序执行的main方法。 6. **main方法能否被...
当`synchronized`关键字用于修饰一个代码块时,它创建了一个同步语句块。例如: ```java synchronized(this) { // 代码块 } ``` 在这个例子中,`this`引用当前对象。这意味着,当一个线程进入这个同步代码块...
2. 使用synchronized关键字进行同步,包括同步方法和同步代码块。 3. sleep()方法属于Thread类,调用后线程进入阻塞状态,而wait()方法属于Object类,调用后线程释放对象锁并进入等待状态。 字符串处理: 1. String...
12. Java中的静态成员:涉及静态变量和实例变量的区别,以及静态方法和非静态方法的调用规则。 对于笔试和面试中遇到的Java相关问题,求职者需要具备扎实的Java基础知识,并能灵活运用这些知识解决实际问题。另外,...
46. Java线程可以通过继承Thread类或实现Runnable接口来创建,synchronized关键字用于同步方法或代码块。 47. sleep是Thread类的方法,使当前线程暂停执行指定的时间;wait是Object类的方法,使当前线程进入等待状态...
不可以,因为非static方法依赖于特定对象实例,而static方法不依赖于任何对象,所以静态方法无法直接调用非静态方法。 13. Integer与int的区别? int是基本数据类型,而Integer是int的包装类。Integer可以存储null...
* JAVA中的同步机制,synchronized关键字、wait、notify等方法。 7. JAVA数据库编程知识点: * JAVA中的JDBC(Java Database Connectivity)编程,Connection、Statement、ResultSet等接口。 * JAVA中的SQL语句...
但是,如果在静态上下文中引用非静态成员,需要先创建外部类的实例。 28. AnonymousInnerClass(匿名内部类)是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)? 匿名内部类既可以继承一个类也...
2. **静态与非静态成员**:在静态方法中不能直接访问类的非静态数据成员,因为静态方法属于类,而非实例对象。 3. **参数传递**:Java中方法调用时参数传递总是按值传递,这意味着在方法内部修改参数不会影响到调用...
- synchronized:同步方法,修饰类方法(即 static 方法)调用前,将把系统类 Class中对应当前类的对象加锁。修饰对象方法(即非 static 方法)调用前,将把当前对象加锁。 7. 接口: - 编程者可以把用于完成特定...
- 构造代码块(非静态代码块)在创建对象时执行,每个实例化过程都会执行一次。 - 局部代码块(方法内的代码块)在进入该代码块时执行。 - 构造方法用于初始化新创建的对象。 2. **继承与类定义**: - 子类可以...
Java支持静态方法和非静态方法,前者与类关联,后者与对象关联。 6. **数组**:在Java中,数组是一种存储固定数量相同类型元素的数据结构。可以是一维、二维或多维数组。 7. **字符串处理**:Java中的`String`类是...
为何使用同步块(synchronized block)而不是同步方法? 同步块比同步方法更精确地控制锁的范围。同步块只锁定特定的代码块,因此其他线程可以访问类的其他方法,而不会阻塞。这样可以减少死锁的风险,并提高多线程...
同步实现方法包括使用synchronized关键字,或者使用java.util.concurrent包中的工具,如ReentrantLock等。 51. 启动线程应该使用start()方法而不是run()方法。start()方法会启动一个新的线程,然后调用run()方法。...
线程同步的常见方法有synchronized关键字、java.util.concurrent.locks包下的Lock和Condition接口等。 应用服务器如Tomcat、WebLogic和WebSphere等。 接口可以继承接口,抽象类可以实现接口,但抽象类不能继承实现...