//
synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法
// 每个对象只有一个锁(lock)与之相关联。
// 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
/*
无论synchronized关键字加在方法上还是对象上,它取得的锁都是锁在了对象上,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。
每个对象只有一个锁(lock)与之相关联。
实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
搞清楚synchronized锁定的是哪个对象,就能帮助我们设计更安全的多线程程序。
还有一些技巧可以让我们对共享资源的同步访问更加安全:
定义private 的instance变量+它的 get方法,而不要定义public/protected的instance变量。如果将变量定义为public,对象在外界可以绕过同步方法的控制而直接取得它,并改动它。
如果instance变量是一个对象,如数组或ArrayList什么的,那上述方法仍然不安全,因为当外界对象通过get方法拿到这个instance对象的引用后,又将其指向另一个对象,那么这个private变量也就变了,岂不是很危险。 这个时候就需要将get方法也加上synchronized同步,并且,只返回这个private对象的clone()――这样,调用端得到的就是对象副本的引用了。
*/
/*
Wait时别的线程可以访问锁定对象
调用wait方法的时候必需锁定该对象
Object提供的方法
Sleep时别的线程也不可以访问锁定对象
Thread提供的方法
*/
public class TestSync implements Runnable {
Timer timer = new Timer();
public static void main(String[] args) {
TestSync test = new TestSync();
Thread t1 = new Thread(test);
Thread t2 = new Thread(test);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
//new Foo().methodBBB();
}
public void run(){
timer.add(Thread.currentThread().getName());
}
}
class Timer {
private int num = 0;
String s = "123";
public void add(String name){
synchronized (s) { // this只当前Timer对象
num ++;
try {Thread.sleep(1);}
catch (InterruptedException e) {}
System.out.println(name+", 你是第"+num+"个使用timer的线程");
}
}
public int readNum() {
return num;
}
}
/
// 第一种情况
// 修饰方法
// 这也就是同步方法,那这时synchronized锁定的是哪个对象呢?
// 它锁定的是调用这个同步方法对象。
// 也就是说,当一个对象P1在不同的线程中执行这个同步方法时,它们之间会形成互斥,达到同步的效果。
// 但是这个对象所属的Class所产生的另一对象P2却可以任意调用这个被加了synchronized关键字的方法。
/
/*
Public synchronized void methodAAA(){
//……
}
*/
//
//
// 第二种情况
// 当有一个明确的对象作为锁时,就可以这样对so这个对象加锁,谁拿到这个锁谁就可以运行它所控制的那段代码
/*
public void method3(SomeObject so){
synchronized(so){
//……
}
}
*/
// /
// 第三种情况
// 但当没有明确的对象作为锁,只是想让一段代码同步时,
// 可以创建一个特殊的instance变量(它得是一个对象)来充当锁:
// 注:零长度的byte数组对象创建起来将比任何对象都经济
// 查看编译后的字节码:
// 生成零长度的byte[]对象只需3条操作码,
// 而Object lock = new Object()则需要7行操作码。
/*
class Foo implements Runnable{
private byte[] lock = new byte[0]; // 特殊的instance变量
Public void methodA(){
synchronized(lock) {
//……
}
}
//……
}
*/
// /
/
// 第四种情况
// 将synchronized作用于static 函数,示例代码如下
// 代码中的methodBBB()方法是把class literal作为锁的情况,它和同步的static函数产生的效果是一样的,
// 取得的锁很特别,是当前调用这个方法的对象所属的类(Class,而不再是由这个Class产生的某个具体对象了)。
// ------>下面的说法可能有问题!
// 如果一个类中定义了一个synchronized的static函数A,也定义了一个synchronized 的instance函数B,
// 那么这个类的同一对象Obj在多线程中分别访问A和B两个方法时,不会构成同步,
// 因为它们的锁都不一样。A方法的锁是Obj这个对象,而B的锁是Obj所属的那个Class。
/*
class Foo {
public synchronized static void methodAAA(){ // 同步的static 函数
try {Thread.sleep(1000);}catch (InterruptedException e) {}
System.out.println("methodAAA......");
}
public void methodBBB(){
synchronized(Foo.class){ // class literal(类名称字面常量)
}
System.out.println(Foo.class.getName() + ".class");
}
}
*/
补充:
// 每个对象只有一个锁(lock)与之相关联。
// 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
/*
无论synchronized关键字加在方法上还是对象上,它取得的锁都是锁在了对象上,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。
每个对象只有一个锁(lock)与之相关联。
实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
搞清楚synchronized锁定的是哪个对象,就能帮助我们设计更安全的多线程程序。
还有一些技巧可以让我们对共享资源的同步访问更加安全:
定义private 的instance变量+它的 get方法,而不要定义public/protected的instance变量。如果将变量定义为public,对象在外界可以绕过同步方法的控制而直接取得它,并改动它。
如果instance变量是一个对象,如数组或ArrayList什么的,那上述方法仍然不安全,因为当外界对象通过get方法拿到这个instance对象的引用后,又将其指向另一个对象,那么这个private变量也就变了,岂不是很危险。 这个时候就需要将get方法也加上synchronized同步,并且,只返回这个private对象的clone()――这样,调用端得到的就是对象副本的引用了。
*/
/*
Wait时别的线程可以访问锁定对象
调用wait方法的时候必需锁定该对象
Object提供的方法
Sleep时别的线程也不可以访问锁定对象
Thread提供的方法
*/
public class TestSync implements Runnable {
Timer timer = new Timer();
public static void main(String[] args) {
TestSync test = new TestSync();
Thread t1 = new Thread(test);
Thread t2 = new Thread(test);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
//new Foo().methodBBB();
}
public void run(){
timer.add(Thread.currentThread().getName());
}
}
class Timer {
private int num = 0;
String s = "123";
public void add(String name){
synchronized (s) { // this只当前Timer对象
num ++;
try {Thread.sleep(1);}
catch (InterruptedException e) {}
System.out.println(name+", 你是第"+num+"个使用timer的线程");
}
}
public int readNum() {
return num;
}
}
/
// 第一种情况
// 修饰方法
// 这也就是同步方法,那这时synchronized锁定的是哪个对象呢?
// 它锁定的是调用这个同步方法对象。
// 也就是说,当一个对象P1在不同的线程中执行这个同步方法时,它们之间会形成互斥,达到同步的效果。
// 但是这个对象所属的Class所产生的另一对象P2却可以任意调用这个被加了synchronized关键字的方法。
/
/*
Public synchronized void methodAAA(){
//……
}
*/
//
//
// 第二种情况
// 当有一个明确的对象作为锁时,就可以这样对so这个对象加锁,谁拿到这个锁谁就可以运行它所控制的那段代码
/*
public void method3(SomeObject so){
synchronized(so){
//……
}
}
*/
// /
// 第三种情况
// 但当没有明确的对象作为锁,只是想让一段代码同步时,
// 可以创建一个特殊的instance变量(它得是一个对象)来充当锁:
// 注:零长度的byte数组对象创建起来将比任何对象都经济
// 查看编译后的字节码:
// 生成零长度的byte[]对象只需3条操作码,
// 而Object lock = new Object()则需要7行操作码。
/*
class Foo implements Runnable{
private byte[] lock = new byte[0]; // 特殊的instance变量
Public void methodA(){
synchronized(lock) {
//……
}
}
//……
}
*/
// /
/
// 第四种情况
// 将synchronized作用于static 函数,示例代码如下
// 代码中的methodBBB()方法是把class literal作为锁的情况,它和同步的static函数产生的效果是一样的,
// 取得的锁很特别,是当前调用这个方法的对象所属的类(Class,而不再是由这个Class产生的某个具体对象了)。
// ------>下面的说法可能有问题!
// 如果一个类中定义了一个synchronized的static函数A,也定义了一个synchronized 的instance函数B,
// 那么这个类的同一对象Obj在多线程中分别访问A和B两个方法时,不会构成同步,
// 因为它们的锁都不一样。A方法的锁是Obj这个对象,而B的锁是Obj所属的那个Class。
/*
class Foo {
public synchronized static void methodAAA(){ // 同步的static 函数
try {Thread.sleep(1000);}catch (InterruptedException e) {}
System.out.println("methodAAA......");
}
public void methodBBB(){
synchronized(Foo.class){ // class literal(类名称字面常量)
}
System.out.println(Foo.class.getName() + ".class");
}
}
*/
补充:
class
Foo
{
static Foo foo = new Foo();
// 同步的static 函数
public synchronized static void methodAAA(){
System.out.println("methodAAA......");
try {
Thread.sleep(5000);
}catch (InterruptedException e) {
}
}
// 同步Foo.class.....说明:class literal(类名称字面常量)
public void methodBBB(){
synchronized(Foo.class){
System.out.println(Foo.class.getName() + ".class");
try {
Thread.sleep(5000);
}catch (InterruptedException e) {
}
}
}
//普通方法
public void methodCCC(){
System.out.println("generic method ......");
try {
Thread.sleep(5000);
}catch (InterruptedException e) {
}
}
}
class TestFoo {
public static void main(String [] args){
//通过不同的实例调用methodAAA
//new Thread(new A()).start();
//new Thread(new A()).start();
//通过不同的实例调用methodBBB
//new Thread(new B()).start();
//new Thread(new B()).start();
//通过不同的实例调用methodAAA和methodBBB
//new Thread(new A()).start();
//new Thread(new B()).start();
//通过相同的实例调用methodAAA
//new Thread(new AA()).start();
//new Thread(new AA()).start();
//通过相同的实例调用methodBBB
//new Thread(new BB()).start();
//new Thread(new BB()).start();
//通过相同的实例调用methodAAA和methodBBB
//new Thread(new AA()).start();
//new Thread(new BB()).start();
//调用普通方法
//Foo.foo.methodCCC();
}
}
class A implements Runnable {
public void run() {
new Foo().methodAAA();
}
}
class B implements Runnable {
public void run() {
new Foo().methodBBB();
}
}
class AA implements Runnable {
public void run() {
Foo.foo.methodAAA();
}
}
class BB implements Runnable {
public void run() {
Foo.foo.methodBBB();
}
}
static Foo foo = new Foo();
// 同步的static 函数
public synchronized static void methodAAA(){
System.out.println("methodAAA......");
try {
Thread.sleep(5000);
}catch (InterruptedException e) {
}
}
// 同步Foo.class.....说明:class literal(类名称字面常量)
public void methodBBB(){
synchronized(Foo.class){
System.out.println(Foo.class.getName() + ".class");
try {
Thread.sleep(5000);
}catch (InterruptedException e) {
}
}
}
//普通方法
public void methodCCC(){
System.out.println("generic method ......");
try {
Thread.sleep(5000);
}catch (InterruptedException e) {
}
}
}
class TestFoo {
public static void main(String [] args){
//通过不同的实例调用methodAAA
//new Thread(new A()).start();
//new Thread(new A()).start();
//通过不同的实例调用methodBBB
//new Thread(new B()).start();
//new Thread(new B()).start();
//通过不同的实例调用methodAAA和methodBBB
//new Thread(new A()).start();
//new Thread(new B()).start();
//通过相同的实例调用methodAAA
//new Thread(new AA()).start();
//new Thread(new AA()).start();
//通过相同的实例调用methodBBB
//new Thread(new BB()).start();
//new Thread(new BB()).start();
//通过相同的实例调用methodAAA和methodBBB
//new Thread(new AA()).start();
//new Thread(new BB()).start();
//调用普通方法
//Foo.foo.methodCCC();
}
}
class A implements Runnable {
public void run() {
new Foo().methodAAA();
}
}
class B implements Runnable {
public void run() {
new Foo().methodBBB();
}
}
class AA implements Runnable {
public void run() {
Foo.foo.methodAAA();
}
}
class BB implements Runnable {
public void run() {
Foo.foo.methodBBB();
}
}