这项练习直接来自Kathy Seirra和Bert Bates的SCJP
同步代码块
在本练习中,我们将尝试同步一段代码。在该代码块中,我们将获得对象的锁定,以便其他线程在代码块执行时无法修改它。我们将创建三个线程,它们都将尝试操作同一个对象。每个线程将输出一个单个字母100次,然后将该字母递增1。我们将使用的对象是StringBuffer。
我们可以在String对象上进行同步,但不能修改一次字符串 它们是创建的,所以如果不生成新的String对象,我们将无法增加字母。最终输出应该有100个As,100个B和100个C,所有这些都是不间断的。
我为上述练习编写了以下课程(而不是100我打印10个字符)
class MySyncBlockTest extends Thread {
StringBuffer sb;
MySyncBlockTest(StringBuffer sb) {
this.sb=sb;
}
public static void main (String args[]) {
StringBuffer sb = new StringBuffer("A");
MySyncBlockTest t1 = new MySyncBlockTest(sb);
MySyncBlockTest t2 = new MySyncBlockTest(sb);
MySyncBlockTest t3 = new MySyncBlockTest(sb);
t1.start();
t2.start();
t3.start();
}
public void run() {
synchronized(this) {
for (int i=0; i<10; i++) {
System.out.print(sb);
}
System.out.println("");
if (sb.charAt(0)=='A')
sb.setCharAt(0, 'B');
else
sb.setCharAt(0, 'C');
}
}
}
我期待的输出类似于以下(10 As,10 B和10 C),但没有得到它。
AAAAAAAAAA
BBBBBBBBBB
CCCCCCCCCC
相反,我得到了不同的输出,如下面的三个线程 在对方完成之前有机会进入循环。
AAAAAAAAAAAAAAAAAA
ABB
ACCCCCCCC
我的问题是为什么run方法中的synchronized块不起作用?
答案 0 :(得分:20)
4。 synchronized代码块将从步骤3获取StringBuffer对象的锁定。
嗯,你不是那样做的,是吗?
synchronized(this) {
您正在调用MySyncBlockTest
方法的run()
实例上获取锁定。那...不会做任何事情。对该资源没有争议;每个Thread
都有自己的MySyncBlockTest
实例。
答案 1 :(得分:4)
你应该锁定StringBuffer对象
synchronized(sb) {
for (int i=0; i<10; i++) {
System.out.print(sb);
}
答案 2 :(得分:1)
我也很困惑。 Brian提供的答案是正确的
synchronized (this){
用于获取实例上的锁定。当有一个类的实例和多个线程访问它时,它会很有用。
我写了以下程序来证明这一点:
package com.threads.chapter9;
public class TestSunchronizedBlocksUsingRunnable implements Runnable {
StringBuffer s;
@Override
public void run() {
synchronized (this) {
for (int i = 1; i <= 100; i++) {
System.out.println(i);
}
char c = s.charAt(0);
c++;
s.setCharAt(0, c);
}
}
TestSunchronizedBlocksUsingRunnable(StringBuffer s) {
this.s = s;
}
public static void main(String[] args) {
StringBuffer s = new StringBuffer("A");
TestSunchronizedBlocksUsingRunnable instance1 = new TestSunchronizedBlocksUsingRunnable(s);
Thread thread1 = new Thread(instance1);
Thread thread2 = new Thread(instance1);
Thread thread3 = new Thread(instance1);
thread1.start();
thread2.start();
thread3.start();
}
}
上面的代码将显示相同的输出,但场景完全不同。因此,在synchronized块中使用的内容非常重要。
答案 3 :(得分:0)
您想要的输出,即单个对象的多个线程可能的输出,请尝试此方法
public class MultiThreading implements Runnable {
public static void main(String [] arg)
{
MultiThreading a=new MultiThreading(20);
Thread t0=new Thread(a); //
Thread t1=new Thread(a); // Multiple Threads of single object
Thread t2=new Thread(a); //
t0.start();
t1.start();
t2.start();
}
private int count;
MultiThreading(int a)
{this.count=a;
}
public void run()
{
synchronized(this){
String t_name=new String("");
t_name=Thread.currentThread().getName().toString();
for(int i=0;i<count;i++)
if(t_name.equals("Thread-0".toString())) // mean t0
System.out.print("A");
else if(t_name.equals("Thread-1".toString())) // mean t1
System.out.print("B");
else if(t_name.equals("Thread-2".toString())) // mean t1
System.out.print("C");
System.out.print("\n");
}
} // end of run
}
答案 4 :(得分:0)
EXERCISE 9-2 from SCJP:
Try this For Synchronozing on stringBuffer Object.
It is giving required output.
class letterThread extends Thread
{
StringBuffer putLetter;
letterThread(StringBuffer str)
{
this.putLetter=str;
}
public void run()
{
synchronized (putLetter) {
if(Thread.currentThread().getName().equals("th2"))
{
this.putLetter=new StringBuffer("B");
}
else if(Thread.currentThread().getName().equals("th3"))
{
this.putLetter=new StringBuffer("C");
}
for(int i=1;i<11;i++)
{
System.out.print(putLetter+"");
}
System.out.println();
}
}
}
public class Manager
{
public static void main(String args[])
{
StringBuffer str=new StringBuffer("A");
letterThread th1=new letterThread(str);
letterThread th2=new letterThread(str);
letterThread th3=new letterThread(str);
th1.setName("th1");
th2.setName("th2");
th3.setName("th3");
th1.start();
th2.start();
th3.start();
}
}
答案 5 :(得分:-1)
从SCJP7开始练习13-2
public class ThreadSyncronization extends Thread {
StringBuffer sBuffer;
public ThreadSyncronization(StringBuffer s,String name){
this.sBuffer=s;
this.setName(name);
}
public ThreadSyncronization(){
}
/**
* @param args
*/
public static void main(String[] args) {
StringBuffer ch = new StringBuffer("A");
Thread t1 = new ThreadSyncronization(ch,"first");
Thread t2 = new ThreadSyncronization(ch,"second");
Thread t3 = new ThreadSyncronization(ch,"third");
t1.start();
t2.start();
t3.start();
}
public void run(){
synchronized (sBuffer) {
System.out.println(this.getName());
for(int i=0;i<10;i++) {
System.out.print(sBuffer+":"+i+" ");
try{Thread.sleep(500);} catch(InterruptedException e) {System.out.println(e);}
}
System.out.println();
// increment char
char c = this.sBuffer.charAt(0);
this.sBuffer.setCharAt(0, ++c);
}
}
}
答案 6 :(得分:-2)
你可以替换
if (sb.charAt(0)=='A')
sb.setCharAt(0, 'B');
else
sb.setCharAt(0, 'C');
与
sb.setCharAt(0, (char) (sb.charAt(0) + 1));
答案 7 :(得分:-4)
package com.practice.ThreadPackage;
类ThreadParent扩展了线程{
StringBuffer data;
public void run() {
synchronized (this.data) {
System.out.println(this.getName());
for (int i = 0; i < 10; i++) {
System.out.print(this.data.toString());
}
System.out.println();
this.data.setCharAt(0, ((char) (this.data.charAt(0) + 1)));
}
}
ThreadParent(StringBuffer obj) {
this.data = obj;
}
}
public class ThreadClass { public static void main(String args []){
StringBuffer str = new StringBuffer("A");
ThreadParent obj = new ThreadParent(str);
ThreadParent obj1 = new ThreadParent(str);
ThreadParent obj2 = new ThreadParent(str);
obj.setName("Thread1");
obj1.setName("Thread2");
obj2.setName("Thread3");
obj.start();
obj1.start();
obj2.start();
}
}