我正在学习如何使用Java中的线程,我需要一些建议..
我想在0..50的标准输出数字上打印使用三个线程完成它的线程的名称。
我有两个类 - 类计数器,用于实现Runnable和类Main ,用于创建和运行线程。 Counter具有变量 c ,它在线程之间共享。
我的想法是,我将 c 增加1,然后在当前线程上调用 yield(),以便其他线程也这样做。重复此操作,直到 c 达到50。
但它不起作用,数字按错误的顺序打印出来。我该如何解决这个问题?
public class Counter implements Runnable {
Thread t1;
private int c = -1;
public Counter() {
}
public Counter(String name) {
t1 = new Thread(this, name);
t1.start();
}
@Override
public void run() {
while (c < 50) {
increment();
Thread.yield();
}
}
public void increment() {
if (c < 50) {
c++;
System.out.println(Thread.currentThread().getName() + ": " + c);
}
}
}
public class Main {
public static void main(String[] args) throws IllegalThreadStateException {
Counter c1 = new Counter();
Thread t1 = new Thread(c1, "Thread 1");
Thread t2 = new Thread(c1, "Thread 2");
Thread t3 = new Thread(c1, "Thread 3");
t1.start();
t2.start();
t3.start();
}
编辑:最后我用这种方式解决了。感谢所有帮助我开始多线程的人。
import java.util.concurrent.atomic.AtomicInteger;
public class Counter2 implements Runnable {
// you could also use simple int
private AtomicInteger c = new AtomicInteger(-1);
private static final Object syncObject = new Object();
public Counter2() {
}
@Override
public void run() {
while (c.get() < 50) {
synchronized (syncObject) {
if (c.get() < 50) {
System.out.println(Thread.currentThread().getName() + ": " + c.incrementAndGet());
}
}
}
}
}
答案 0 :(得分:2)
在方法增量中使用syncrhonized部分和特殊的静态对象。
private static final Object syncObj = new Object();
public void increment()
{
syncrhonized( syncObj )
{
c++;
System.out.println(c);
}
}
或者通过声明使这个方法同步。
但是将真实数据存储在线程对象中是错误的。线程应该只使用共享对象进行操作,而不是存储它们。 实际上我不明白你为什么要开始使用
答案 1 :(得分:1)
使increment()
同步,以防止其他线程同时进入该方法。
与yield()
一起你应该能够让另一个线程打印下一个数字(并不总是因为系统可能会再次恢复调用yield
的线程 - 请参阅Ingo的答案 - 但是顺序应该仍然是相同的)。
synchronized increment()
意味着任何试图在同一个对象上输入该方法的线程都必须等待,如果另一个线程已经通过输入方法获得了锁。
答案 2 :(得分:1)
引用javadoc Thread.yield(),我强调:
public static void yield()
提示调度程序 目前的线程愿意屈服于它 当前使用的处理器。的的 调度程序可以自由地忽略它 提示强>
...
很少适合使用 这种方法。
答案 3 :(得分:1)
是的,您的代码无效。 Thread#yield()不会以您希望的方式控制线程调度程序。我很好奇你得到了什么结果。你可能会得到重复的数字和一些稍微不正常的数字。
您可以使用原子整数来删除所有重复项。但由于print语句不是原子的。您仍可能无序打印结果。所以你应该只是同步增量方法。你也不需要收益,所以转储它。
如果问题的目的是从线程1到线程2再到线程3回到线程1等等......结果是
Thread 1:0
Thread 2:1
Thread 3:2
Thread 1:3
Thread 2:4
Thread 3:5
Thread 1:6
Thread 2:7
....
然后你需要锁定increment方法并使用wait和notifyAll。 wait将导致其他线程暂停处理,直到当前线程通知它们再次启动。