1.内置类和静态内置类
关键字synchronized的知识点还涉及内置类的使用。先来看一下简单的内置类测试。
package test;
/**
* @Author LiBinquan
*/
public class PublicClass {
private String userName;
private String passWord;
class PrivateClass {
private String age;
private String address;
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public void printPublicProperty(){
System.out.println(userName + " "+passWord);
}
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
}
运行类:
package test;
/**
* @Author LiBinquan
*/
public class Run {
public static void main(String[] args) throws InterruptedException {
PublicClass publicClass = new PublicClass();
publicClass.setUserName("AA");
publicClass.setPassWord("aaa");
System.out.println(publicClass.getUserName() + " "+publicClass.getPassWord());
PublicClass.PrivateClass privateClass = publicClass.new PrivateClass();
privateClass.setAge("13");
privateClass.setAddress("addressValue");
System.out.println(privateClass.getAge()+" "+privateClass.getAddress());
}
}
输出:
如果PublicClass.java类和Run.java类不在同一个包中,则需要将PrivateClass内置声明public公开的。测试代码如下:
package test;
/**
* @Author LiBinquan
*/
public class PublicClass {
static private String userName;
static private String passWord;
static class PrivateClass {
private String age;
private String address;
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public void printPublicProperty(){
System.out.println(userName + " "+passWord);
}
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
}
运行类:
package test;
/**
* @Author LiBinquan
*/
public class Run {
public static void main(String[] args) throws InterruptedException {
PublicClass publicClass = new PublicClass();
publicClass.setUserName("AA");
publicClass.setPassWord("aaa");
System.out.println(publicClass.getUserName() + " "+publicClass.getPassWord());
PublicClass.PrivateClass privateClass = new PublicClass.PrivateClass();
privateClass.setAge("13");
privateClass.setAddress("addressValue");
System.out.println(privateClass.getAge()+" "+privateClass.getAddress());
}
}
输出:
接下来做几个测试:
1.内置类中有2个同步方法,但使用的却是不同的锁,打印的结果也是异步。
package test;
/**
* @Author LiBinquan
*/
public class OutClass {
static class Inner{
public void method1(){
synchronized ("锁1"){
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+" i = "+i);
try{
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
public synchronized void method2(){
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+" i = "+i);
try{
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
}
运行类:
package test;
/**
* @Author LiBinquan
*/
public class Run {
public static void main(String[] args) throws InterruptedException {
final OutClass.Inner inner = new OutClass.Inner();
Thread t1 = new Thread(new Runnable(){
public void run (){
inner.method1();
}
},"A");
Thread t2 = new Thread(new Runnable(){
public void run (){
inner.method2();
}
},"B");
t1.start();
t2.start();
}
}
输出:
由输出可得,持有不同的“对象监视器”,所以打印结果就是无序的。
2.同步代码块(class2)对class2上锁后,其他线程只能以同步的方式调式用class2中的静态同步方法。
package test;
/**
* @Author LiBinquan
*/
public class OutClass {
static class Inner1{
public void method1(Inner2 class2){
String threadName = Thread.currentThread().getName();
synchronized (class2){
System.out.println(threadName +"进入 Inner1 类中的 method1 方法");
for (int i = 0; i < 10; i++) {
System.out.println("i = "+i);
try{
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
}
System.out.println(threadName +"离开 Inner1 类中的 method1 方法");
}
}
public synchronized void method2(){
String threadName = Thread.currentThread().getName();
System.out.println(threadName +"进入 Inner1 类中的 method2 方法");
for (int k = 0; k < 20; k++) {
System.out.println(" k = "+k);
try{
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
}
System.out.println(threadName +"离开 Inner1 类中 method2 方法");
}
}
static class Inner2{
public synchronized void method1(){
String threadName = Thread.currentThread().getName();
System.out.println(threadName + "进入 Inner2 类中的method1 方法");
for (int i = 0; i < 10; i++) {
System.out.println(" m = "+i);
try{
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
}
System.out.println(threadName + "离开入 Inner2 类中的method1 方法");
}
}
}
运行类:
package test;
/**
* @Author LiBinquan
*/
public class Run {
public static void main(String[] args) throws InterruptedException {
final OutClass.Inner1 inner1 = new OutClass.Inner1();
final OutClass.Inner2 inner2 = new OutClass.Inner2();
Thread t1 = new Thread(new Runnable(){
public void run (){
inner1.method1(inner2);
}
},"A");
Thread t2 = new Thread(new Runnable(){
public void run (){
inner1.method2();
}
},"B");
Thread t3 = new Thread(new Runnable(){
public void run (){
inner2.method1();
}
},"C");
t1.start();
t2.start();
t3.start();
}
}
输出:
2.锁对象的改变
在将任何数据类型作为同步锁时,需要注意的是,是否有多个线程同时持有锁对象,如果同时持有相同的锁对象,则这些线程之间就是同步的;如果分别获得锁对象,这些线程就是异步的。
package test;
/**
* @Author LiBinquan
*/
public class MyService {
private String lock = "123";
public void testMethod(){
try{
synchronized (lock){
System.out.println(Thread.currentThread().getName()+" begin "+System.currentTimeMillis());
lock = "456";
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName()+" end "+System.currentTimeMillis());
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
线程1:
package test;
/**
* @Author LiBinquan
*/
public class ThreadTest1 extends Thread{
private MyService service;
public ThreadTest1(MyService service){
super();
this.service = service;
}
@Override
public void run() {
service.testMethod();
}
}
线程2:
package test;
/**
* @Author LiBinquan
*/
public class ThreadTest2 extends Thread{
private MyService service;
public ThreadTest2(MyService service){
super();
this.service = service;
}
@Override
public void run() {
service.testMethod();
}
}
运行类:
package test;
/**
* @Author LiBinquan
*/
public class Run {
public static void main(String[] args) throws InterruptedException {
MyService service = new MyService();
ThreadTest1 a = new ThreadTest1(service);
a.setName("A");
ThreadTest2 b = new ThreadTest2(service);
b.setName("B");
a.start();
Thread.sleep(50);
b.start();
}
}
输出:
因为50毫秒过后线程B取得的锁是“456”。
去掉Thread.sleep(50),代码如下:
package test;
/**
* @Author LiBinquan
*/
public class Run {
public static void main(String[] args) throws InterruptedException {
MyService service = new MyService();
ThreadTest1 a = new ThreadTest1(service);
a.setName("A");
ThreadTest2 b = new ThreadTest2(service);
b.setName("B");
a.start();
b.start();
}
}
输出:
这时线程1和线程2的锁都是“123”,虽然将随改成了“456”,但是结果还是同步的,因为1和2共同争抢的锁是“123”。
注意:只要对象不变,及时对象的属性被改变,运行的结果还是同步。测试代码如下,
package test;
/**
* @Author LiBinquan
*/
public class Service {
public void serviceMethodA(User user){
synchronized (user){
try{
System.out.println(Thread.currentThread().getName());
user.setUserName("abc");
Thread.sleep(3000);
System.out.println("end time = "+System.currentTimeMillis());
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
线程1:
package test;
/**
* @Author LiBinquan
*/
public class ThreadTest1 extends Thread{
private Service service;
private User user;
public ThreadTest1(Service service,User user){
super();
this.service = service;
this.user = user;
}
@Override
public void run() {
service.serviceMethodA(user);
}
}
线程2:
package test;
/**
* @Author LiBinquan
*/
public class ThreadTest2 extends Thread{
private Service service;
private User user;
public ThreadTest2(Service service,User user){
super();
this.service = service;
this.user = user;
}
@Override
public void run() {
service.serviceMethodA(user);
}
}
运行类:
package test;
/**
* @Author LiBinquan
*/
public class Run {
public static void main(String[] args) throws InterruptedException {
try{
Service service = new Service();
User user = new User();
ThreadTest1 t1 = new ThreadTest1(service,user);
t1.setName("A");
t1.start();
Thread.sleep(50);
ThreadTest2 t2 = new ThreadTest2(service,user);
t2.setName("B");
t2.start();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
输出: