[英]Synchronized block not working
这个练习直接来自 Kathy Seirra 和 Bert Bates 的 SCJP
同步代码块
在本练习中,我们将尝试同步代码块。 在那个代码块中,我们将获得一个对象的锁,这样在代码块执行时其他线程就不能修改它。 我们将创建三个线程,它们都将尝试操作同一个对象。 每个线程将输出单个字母 100 次,然后将该字母递增 1。 我们将使用的对象是 StringBuffer。
我们可以在 String 对象上进行同步,但是字符串一旦创建就无法修改,因此如果不生成新的 String 对象,我们将无法增加字母。 最终输出应该有 100 个 As、100 个 Bs 和 100 个 Cs,所有这些都在不间断的行中。
我已经为上述练习编写了以下课程(而不是 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 Bs 和 10 Cs)但没有得到它。
AAAAAAAAAA
BBBBBBBBBB
CCCCCCCCCC
相反,我得到了如下不同的输出,因为三个线程有机会在另一个线程完成之前进入循环。
AAAAAAAAAAAAAAAAAA
ABB
ACCCCCCCC
我的问题是为什么 run 方法中的 synchronized 块不起作用?
4. 同步代码块将从步骤 3 中获取对 StringBuffer 对象的锁定。
好吧,你不会那样做,是吗?
synchronized(this) {
您正在获取对MySyncBlockTest
run()
方法的MySyncBlockTest
实例的锁定。 那……不会做任何事情。 没有对该资源的争用; 每个Thread
都有自己的MySyncBlockTest
实例。
您应该锁定 StringBuffer 对象
synchronized(sb) {
for (int i=0; i<10; i++) {
System.out.print(sb);
}
我也很困惑。 布赖恩提供的答案是正确的
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 块中使用的内容非常重要。
您想要的输出,单个对象的多个线程是可能的,试试这个方法
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();
}
}
练习 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);
}
}
}
你可以更换
if (sb.charAt(0)=='A')
sb.setCharAt(0, 'B');
else
sb.setCharAt(0, 'C');
和
sb.setCharAt(0, (char) (sb.charAt(0) + 1));
包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;
}
}
公共类线程类 { 公共静态无效主(字符串参数 []){
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.