最近阅读网上关于synchronized块的资料,说法也不尽相同,经过自己代码测试,以下仅为个人理解,如有错误,麻烦指出问题所在,谢谢~
synchronized块参数表示的是以什么为锁,参数可以为固定字符串,this,数组对象等等,但不能为int等8种基本数据类型,只有锁相同,才能导致等待。
public class SynchronizedKuai{
private static int i = 0;
private static byte[] lock = new byte[0];;
public void A(){
synchronized(lock){
System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++");
i++;
System.out.println("调用了++,当前值为:"+i);
for (int j = 0; j < 1000000000; j++) {
}
System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++");
i++;
System.out.println("调用了++,当前值为:"+i);
}
}
public void B(){
synchronized(lock){
i--;
System.out.println("======================================================");
System.out.println("调用了--,当前值为:"+i);
}
}
public static void main(String[] args) {
Sub sub = new Sub();
Add add = new Add();
Thread th1 = new Thread(sub);
th1.start();
Thread th2 = new Thread(add);
th2.start();
}
}
class Sub implements Runnable{
@Override
public void run() {
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SynchronizedKuai synchronizedKuai = new SynchronizedKuai();
synchronizedKuai.B();
}
}
}
class Add implements Runnable{
@Override
public void run() {
while(true){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SynchronizedKuai synchronizedKuai = new SynchronizedKuai();
synchronizedKuai.A();
}
}
}
如上例子,对于两个线程可以锁住。然而对于如下例子,却锁不住。
public class SynchronizedKuai{
private static int i = 0;
public void A(){
synchronized(this){
System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++");
i++;
System.out.println("调用了++,当前值为:"+i);
for (int j = 0; j < 1000000000; j++) {
}
System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++");
i++;
System.out.println("调用了++,当前值为:"+i);
}
}
public void B(){
synchronized(this){
i--;
System.out.println("======================================================");
System.out.println("调用了--,当前值为:"+i);
}
}
public static void main(String[] args) {
Sub sub = new Sub();
Add add = new Add();
Thread th1 = new Thread(sub);
th1.start();
Thread th2 = new Thread(add);
th2.start();
}
}
class Sub implements Runnable{
@Override
public void run() {
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SynchronizedKuai synchronizedKuai = new SynchronizedKuai();
synchronizedKuai.B();
}
}
}
class Add implements Runnable{
@Override
public void run() {
while(true){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SynchronizedKuai synchronizedKuai = new SynchronizedKuai();
synchronizedKuai.A();
}
}
}
两个例子看似相同,但是其实synchronized快的锁其实并不相同,当使用的是this时,锁为对象,它是两个对象,对同一数据操作不会等待,而使用byte长度为0的数组开销是最小的,如果不使用静态的byte数组,对于两个不同对象的线程,是两个不同的byte数组,两个线程线程也无法锁住synchronized快。
以下部分为学习时看到不错的经验。
有一些技巧可以让我们对共享资源的同步访问更加安全:
1. 定义private 的instance变量+它的 get方法,而不要定义public/protected的instance变量。如果将变量定义为public,对象在外界可以绕过同步方法的控制而直接取得它,并改动它。这也是JavaBean的标准实现方式之一。
2. 如果instance变量是一个对象,如数组或ArrayList什么的,那上述方法仍然不安全,因为当外界对象通过get方法拿到这个instance对象的引用后,又将其指向另一个对象,那么这个private变量也就变了,岂不是很危险。 这个时候就需要将get方法也加上synchronized同步,并且,只返回这个private对象的clone()――这样,调用端得到的就是对象副本的引用了。
注意:对于使用clone()方法的使用:实例调用clone方法就需要让此类实现Cloneable接口,API里面还有句话是:如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException 异常,这便是“合法”的含义。 但请注意,Cloneable接口只是个标签接口,不含任何需要实现的方法,就像Serializable接口一样。例如:
class Employee implements Cloneable
{
public Employee clone() throws CloneSupportedException
{
return (Employee)super.clone();
}
}
你看到clone()是Object的方法,而Object是所有类的父类,就认为可以用Object调用 clone是么?
但不能使用Object调用clone()方法,原因如下:
1.从你写法本身来看,Object.clone()肯定不行,因为Object是类, 而clone()是成员方法,所以不能用Object.clone();
2.那么是不是可以先Object obj=new Object();再obj.clone();或者Object.class.newInstance().clone()呢?还是不行。
clone()对Object类对象本身是不可见的。所以你会发现找不到clone()方法
原因是:clone()方法是protected访问权限
方法原型:protected native java.long.Object clone() throws java.long.CloneNotSupportedException
而protected权限的含义是:只对同一包中的类和不同包中的子类及间接子类可访问,换句话说就是不同包中的非子类或间接子类不能访问,包含了默认的包访问权限。
这个地方容易混淆哦
你可能会问任何类都是Object的子类为什么不能访问呢,对,任何类是他的子类也继承了clone()方法
但请注意,你那句代码clone()的调用者是谁?是Object本身,即Object对象,正如我们所说,“不同包中的非子类或间接子类不能访问”,这里面也包括了父类本身,你调用者是父类,在不同包中,protected成员对父类不可见哦,所以根本不能用object对象调用clone()
综上,因为在不同包中父类本身不能调用,也找不到protected方法 ,故无法在代码中使用object直接调用clone()方法,有点难理解,关键在对protected的理解上,因为protected除了本身在继承上的访问权限外,还包含了包访问权限~