我有一个问题,我必须以这种格式打印数字。
First 1
First 2
Second 3
Second 4
First 5
First 6
Second 7
Second 8
First 9
and so on...
我已经实现了我的runnable接口,如下所示。
class ThreadDemo implements Runnable {
public volatile Integer num;
public Object lock;
public ThreadDemo(Integer num, Object lock) {
this.num = num;
this.lock = lock;
}
@Override
public void run() {
try {
while (true) {
int count = 0;
synchronized(lock) {
Thread.sleep(100);
while (count < 2) {
System.out.println(Thread.currentThread().getName() + " " + num++);
count++;
}
lock.notify();
lock.wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
我的主要课程如下
public class CoWorkingThreads {
private static volatile Integer num = new Integer(1);
public static void main(String...args) {
Object lock = new Object();
Thread thread1 = new Thread(new ThreadDemo(num, lock), "First");
thread1.start();
Thread thread2 = new Thread(new ThreadDemo(num, lock), "Second");
thread2.start();
}
}
当我运行程序时,我得到如下输出
First 1
First 2
Second 1
Second 2
First 3
First 4
Second 3
Second 4
而不是以前预期的结果。但是当我将整数更改为原子整数类型时,我开始得到预期的结果。任何人都可以解释我能做什么使它运行整数而不是使用原子整数
我仍然认为这个问题没有得到正确回答。这里的缺陷是你从未将共享数据标记为static
。所以每个线程都有自己的副本独立于另一个。 Integer
是一个不可变的包装类,这是真的,但它在这种情况下无关。让我们更多地了解num++
。 ++
运算符仅适用于(原始)整数类型。在幕后,num
未装箱,应用++
,然后将结果分配回num
(拳击转换后)。 Integer
类没有++
运算符。事实上,Integer
对象是不可变的。
每次递增和创建新的值对象时,不可变。并且该新值对象将分配回您的num
参考。但是两个线程有自己的num
引用副本指向不同的Integer
盒装基元。因此,它们彼此独立地增加,而另一个则不可见。如果要在线程之间共享它,则必须在声明站点使用static
访问修饰符。将两个值传递给共享变量的更多信息没有意义。相反,您可以内联初始化它。这是固定版本。
public class ThreadDemo implements Runnable {
public static Integer num = 1;
public static final Object lock = new Object();
public ThreadDemo() {
}
@Override
public void run() {
try {
while (true) {
int count = 0;
synchronized (lock) {
Thread.sleep(100);
while (count < 2) {
System.out.println(Thread.currentThread().getName() + " " + num++);
count++;
}
lock.notify();
lock.wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class CoWorkingThreads {
public static void main(String[] args) {
Thread thread1 = new Thread(new ThreadDemo(), "First");
thread1.start();
Thread thread2 = new Thread(new ThreadDemo(), "Second");
thread2.start();
}
}
最后使用客户端提供的锁定对象违反了同步策略的封装。所以我使用了内部私有锁对象。
这是新的输出。
前1前2后2后4前5前5后6后7后8前9后10
Java Integer不能通过引用传递。在您的代码中,每个线程都将创建变量的副本。但是,atomicInteger可以通过引用传递。
另外,要获得正确的结果,可以将num变量更改为静态变量。
public static Integer num = 1;
public Object lock;
public ThreadDemo(Integer num, Object lock) {
//this.num = num;
this.lock =lock;
}
仅仅为了你的知识,而不是在synchronized
上使用Object
块,你可能想要试验Lock
(s)(例如ReentrantLock
)及其相关的Condition
(s)。
使用Condition
,您可以在线程之间以互斥的方式管理共享资源。