当前位置: 首页 > 后端技术 > Java

java培训:多个线程同时访问一个类是否有问题

时间:2023-04-01 13:49:41 Java

Java培训:多个线程同时访问一个类有问题吗?省略getter.setter,下同)publicsynchronizedvoidmethod1(){System.out.println("同步方法1进入");for(inti=0;i<10;i++){System.out.print("同步方法一:"+num+"--");num++;}System.out.println("同步方法一结束");}publicsynchronizedvoidmethod2(){System.out.println("方法二进入:");for(inti=0;i<10;i++){System.out.print("method2:"+num+"--");num++;}System.out.println("method2end");}publicstaticvoidmain(String[]args){finalExample1example1=newExample1();Threadthread1=newThread(newRunnable(){@Overridepublicvoidrun(){example1.method1();}});Threadthread2=newThread(newRunnable(){@Overridepublicvoidrun(){example1.method2();}});try{thread2.join();thread1.join();thread1.start();thread2.start();}catch(InterruptedExceptione){//TODO自动生成的catchblocke.printStackTrace();}}}输出结果:方法1进入同步方法1:0--同步方式1:1--同步方式1:2--同步方式1:3--同步方式1:4--同步方式1:5--同步方式1:6--同步方式1:7--同步方法1:8--同步方法1:9--方法1结束方法2进入:方法2:10--方法2:11--方法2:12--方法2:13--方法2:14--方法2:15--方法2:16--method2:17--method2:18--method2:19--method2ends显然此时多线程不能访问同一个类(一个实例对象)的两个同步方法2.more两个同步方法为两个线程同时访问同一个类的不同实例对象:对上面的代码稍作修改,在main函数中添加一个新的类的实例finalExample1example2=newExample1();然后修改thread2的run方法调用类实例为example2Threadthread2=newThread(newRunnable(){@Overridepublicvoidrun(){example2.method2();}});得到结果:同步方法1进入方法2进入:method2:0--method2:1--syncmethod1:0--syncmethod1:1--syncmethod1:2--method2:2--syncmethod1:3--method2:3--syncmethod1:4--method2:4--synchronousmethod1:5--method2:5--synchronousmethod1:6--synchronousmethod1:7--method2:6--synchronousmethod1:8--synchronousmethod1:9--method2:7--同步方法1结束method2:8--method2:9--method2结束此时,很明显,多线程是两个可以访问的同步方法的总结同一个类(不同的实例对象):这是因为synchronized是对象锁,即一个线程获得的锁是加在一个实例对象上的。如果不同线程访问同一个对象的不同同步方法,那么显然不能同时执行。如果是不同对象上的不同同步方式,那么可以同时进行。3、多个线程同时访问同一个类实例对象的两个Runnable对象的run方法:packagesynchronizedTest;公共类Example2{privateintnum;publicRunnablerunnable1=newRunnable(){@Overridepublicvoidrun(){//同步锁synchronized(this){System.out.println("线程1进入");for(inti=0;i<10;i++){System.out.print("线程1:"+num+"--");}System.out.println("线程1结束");}}};publicRunnablerunnable2=newRunnable(){@Overridepublicvoidrun(){//同步锁synchronized(this){System.out.println("thread2enter");for(inti=0;i<10;i++){System.out.print("thread2:"+num+"--");}System.out.println("thread2end");}}};publicstaticvoidmain(String[]args){Example2example=newExample2();//创建一个对象newThread(example.runnable1).start();//同步方法1newThread(example.runnable2).start();//同步方式2}}输出结果:thread2进入线程1,进入thread2:0--thread1:0--thread1:0--thread2:0--Thread1:0--Thread1:0--线程1:0--thread2:0--线程1:0--thread2:0--thread2:0--线程1:0--thread2:0--thread1:0--thread2:0--thread2:0--thread1:0--thread2:0--thread1:0--thread2:0--thread1结束thread2最后可以看出,多个线程可以同时访问同一个类的两个同步方法。这是因为synchronized(this){//...}中的锁不是代码块,即锁在run方法中。但是run方法不是synchronized的,而是括号里的对象this。也就是说,多个线程会得到自己的锁,可以同时执行run方法。(在run方法前声明synchronized效果相同)newThread(example.runnable1).start();//同步方法1newThread(example.runnable2).start();//同步方法2打印出thisthis对象,是两个不同的类实例对象:synchronizedTest.Example2$1@65db6dfasynchronizedTest.Example2$2@471fab也说明了不同线程的实例对象是不一样的,都是自己对象的锁,和例1对象不能认为是同一个实例,应该和例2中不同类型的实例对象相似lockedobject2.ReentrantLocklock1.多个线程同时访问同一个类实例对象两种同步方式:将例1中的synchronized改为importReentrantLockpackageReentrantLockTest;importjava.util.concurrent.locks.Lock;importjava.util.concurrent.locks.ReentrantLock;publicclassLockExample{privateintnum;privateLocklock=newReentrantLock();publicvoidmethod1(){lock.lock();System.out.println("同步方法1进入");for(inti=0;i<10;i++){System.out.print("同步方式一:"+num+"--");num++;}System.out.println("同步方式一结束");lock.unlock();}publicvoidmethod2(){lock.lock();System.out.println("method2enter:");for(inti=0;i<10;i++){System.out.print("method2:"+num+"--");num++;}System.out.println("method2end");罗ck.unlock();}publicstaticvoidmain(String[]args){finalLockExampleexample=newLockExample();Threadthread1=newThread(newRunnable(){@Overridepublicvoidrun(){example.method1();}});Threadthread2=newThread(newRunnable(){@Overridepublicvoidrun(){example.method2();}});try{thread2.join();thread1.join();thread1.start();thread2.start();}catch(InterruptedExceptione){e.printStackTrace();}}}输出结果:同步方法1进入同步方法1:0--同步方法1:1--同步方法1:2--同步方式1:3--同步方式1:4--同步方式1:5--同步方式1:6--同步方式1:7--同步方式1:8--同步方式1:9--同步方法1结束method2进入:method2:10--method2:11--method2:12--method2:13--method2:14--method2:15--method2:16--method2:17--method2:18--method2:19--method2结束。可以看出,此时多线程不能同时访问同一个类的两个同步方法(同一个类的一个实例对象)。2、多个线程同时访问同一个类的不同实例对象两种同步方式:修改main函数即可:publicstaticvoidmain(String[]args){finalLockExampleexample1=newLockExample();//两个实例finalLockExampleexample2=newLockExample();Threadthread1=newThread(newRunnable(){@Overridepublicvoidrun(){example1.m方法1();//实例1的同步方法1}});Threadthread2=newThread(newRunnable(){@Overridepublicvoidrun(){example2.method2();//实例2的同步方法2}});try{thread2.join();thread1.join();thread1.start();thread2.start();}catch(InterruptedExceptione){e.printStackTrace();}}输出结果:同步方法1进入方法2进入:sync方法1:0--method2:0--method2:1--sync方法1:1--method2:2--sync方法1:2--sync方法1:3--method2:3---sync-method1:4--method2:4--sync-method1:5--sync-method1:6--method2:5--sync-method1:7--method2:6--sync-method1:8--同步方法1:9--同步方法1结束method2:7--method2:8--method2:9--method2结束可见,多线程就是两个同步可以访问同一个类(不同实例对象)的方法总结:ReentrantLock和synchronized前两个例子的结论是一样的。3、多个线程同时访问同一个类实例对象的两个Runnable对象的run方法:packageReentrantLockTest;导入java.util.concurrent.locks.Lock;importjava.util.concurrent.locks.ReentrantLock;publicclassLockexample2{privateintnum;privateLocklock=newReentrantLock();publicRunnablerunnable1=newRunnable(){@Overridepublicvoidrun(){lock.lock();//LockSystem.out.println("线程1进入");for(inti=0;i<10;i++){System.out.print("线程1:"+num+"--");}System.out.println("Thread1ends");lock.unlock();}};publicRunnablerunnable2=newRunnable(){@Overridepublicvoidrun(){lock.lock();//锁定系统.out.println("thread2enter");for(inti=0;i<10;i++){System.out.print("thread2:"+num+"--");}System.out.println("thread2end");lock.unlock();}};publicstaticvoidmain(String[]args){Lockexample2example=newLockexample2();newThread(example.runnable1).start();newThread(example.runnable2).start();}}输出:线程1进入Thread1:0--Thread1:0--Thread1:0--Thread1:0--Thread1:0--Thread1:0--Thread1:0--Thread1:0--Thread1:0--Thread1:0--Thread1结束thread2进入thread2:0--thread2:0--thread2:0--thread2:0--thread2:0--thread2:0--thread2:0--thread2:0--thread2:0--thread2:0--thread2end这里可以看到synchronized的第三个例子在这个其他地方有不同的结果,ReentrantLock不允许多个线程同时访问一个类的不同同步方法。这里要注意ReentrantLock和synchronized是不一样的。ReentrantLock的实现是先创建一个ReentrantLock对象,然后使用这个对象的方法对其进行加锁。一个类实例中只有一个ReentrantLock对象:privateLocklock=newReentrantLock();而在这个例子中,线程的创建是基于同一个类实例:Lockexample2example=newLockexample2();newThread(example.runnable1).start();newThread(example.runnable2).start();所以,ReentrantLock对象锁也是一样的,所以第一个线程进入同步方法1后获取到了锁,而第二个线程获取不到这个锁,只能等待。如果换成两个实例对象:(example2.runnable2).start();}输出结果线程1进入线程2进入线程1:0--线程1:0--线程1:0--线程1:0--线程2:0--线程1:0--thread2:0--thread2:0--thread2:0--thread2:0--thread2:0--thread2:0--thread2:0--thread1:0--thread2:0--线程1:0--Thread1:0--thread2:0--Thread1:0--thread2endsThread1:0--Thread1ends可以看出不同的实例对象是不同的ReentrantLock对象,所以可以访问同时总结:ReentrantLock锁的核心和ReentrantLock对象一样吗?3.结论再看这道题:一个类中的两个方法都有同步锁。多个线程可以同时访问这个类的两个方法吗?现在应该清楚了,这个问题应该分为两种情况:synchronized和ReentrantLock:1.对于一个synchronized类中的两个方法,都加了同步锁,多个线程不能访问this的同一个实例对象的两个方法同时类中一个类中的两个方法都有同步锁,多个线程可以同时访问这个类不同实例对象的两个方法。线程可以同时访问这个类的两个方法(不管它们是不是同一个实例对象)。方法(无论是在实例方法还是run方法中加入同步)一个类中的两个方法是同步的,多个线程可以同时访问该类不同实例对象的两个方法(与实例中加入的同步无关)方法或者run方法中)文章来自Java面试攻略宝典