[英]Synchronized block not working
This exercise is straight out of SCJP by Kathy Seirra and Bert Bates这个练习直接来自 Kathy Seirra 和 Bert Bates 的 SCJP
Synchronizing a Block of Code同步代码块
In this exercise we will attempt to synchronize a block of code.在本练习中,我们将尝试同步代码块。 Within that block of code we will get the lock on an object, so that other threads cannot modify it while the block of code is executing.
在那个代码块中,我们将获得一个对象的锁,这样在代码块执行时其他线程就不能修改它。 We will be creating three threads that will all attempt to manipulate the same object.
我们将创建三个线程,它们都将尝试操作同一个对象。 Each thread will output a single letter 100 times, and then increment that letter by one.
每个线程将输出单个字母 100 次,然后将该字母递增 1。 The object we will be using is StringBuffer.
我们将使用的对象是 StringBuffer。
We could synchronize on a String object, but strings cannot be modified once they are created, so we would not be able to increment the letter without generating a new String object.我们可以在 String 对象上进行同步,但是字符串一旦创建就无法修改,因此如果不生成新的 String 对象,我们将无法增加字母。 The final output should have 100 As, 100 Bs, and 100 Cs all in unbroken lines.
最终输出应该有 100 个 As、100 个 Bs 和 100 个 Cs,所有这些都在不间断的行中。
I have written the below class for the above exercise (instead of 100 I am printing 10 characters)我已经为上述练习编写了以下课程(而不是 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');
}
}
}
I was expecting an output something like the following (10 As, 10 Bs and 10 Cs) but did not get it.我期待输出类似于以下内容(10 As、10 Bs 和 10 Cs)但没有得到它。
AAAAAAAAAA
BBBBBBBBBB
CCCCCCCCCC
Instead I got varying outputs like the following as the three threads are getting a chance to get into the loop before the other has finished.相反,我得到了如下不同的输出,因为三个线程有机会在另一个线程完成之前进入循环。
AAAAAAAAAAAAAAAAAA
ABB
ACCCCCCCC
My question is why is the synchronized block in the run method not working?我的问题是为什么 run 方法中的 synchronized 块不起作用?
4. The synchronized block of code will obtain a lock on the StringBuffer object from step 3.
4. 同步代码块将从步骤 3 中获取对 StringBuffer 对象的锁定。
Well, you're not doing that, are you?好吧,你不会那样做,是吗?
synchronized(this) {
You're obtaining a lock on the instance of MySyncBlockTest
on which that run()
method is being called.您正在获取对
MySyncBlockTest
run()
方法的MySyncBlockTest
实例的锁定。 That ... isn't going to do anything.那……不会做任何事情。 There's no contention for that resource;
没有对该资源的争用; each
Thread
has its own instance of MySyncBlockTest
.每个
Thread
都有自己的MySyncBlockTest
实例。
You should lock on the StringBuffer object您应该锁定 StringBuffer 对象
synchronized(sb) {
for (int i=0; i<10; i++) {
System.out.print(sb);
}
I was confused too.我也很困惑。 The answer provided by Brian is correct
布赖恩提供的答案是正确的
synchronized (this){
is for getting the lock on an instance.用于获取实例的锁。 It would be useful when there is a single instance of a class and multiple threads accessing it.
当有一个类的单个实例和多个线程访问它时,它会很有用。
I wrote the following program to demonstrate 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();
}
}
The above code will display the same output but the scenario is completely different.上面的代码将显示相同的输出,但场景完全不同。 So what you use inside synchronized block is really crucial.
所以你在 synchronized 块中使用的内容非常重要。
The output that you want, thats possible with multiple threads of single object, try this method您想要的输出,单个对象的多个线程是可能的,试试这个方法
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
}
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();
}
}
EXERCISE 13-2 from SCJP7练习 13-2 从 SCJP7
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);
}
}
}
You could replace你可以更换
if (sb.charAt(0)=='A')
sb.setCharAt(0, 'B');
else
sb.setCharAt(0, 'C');
with和
sb.setCharAt(0, (char) (sb.charAt(0) + 1));
package com.practice.ThreadPackage;包com.practice.ThreadPackage;
class ThreadParent extends Thread {类 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();
}
} }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.