Java 如果线程不';不改变状态?
为了测试我的理解能力,我编写了一个小程序,它以特定的顺序写Java 如果线程不';不改变状态?,java,multithreading,concurrency,synchronization,Java,Multithreading,Concurrency,Synchronization,为了测试我的理解能力,我编写了一个小程序,它以特定的顺序写左右 public class LeftRightWaitNotifyExample { final static String str = "1"; public static void main(String[] args) throws InterruptedException { new LeftLegThread(str).start(); Thread.sleep(100);
左右
public class LeftRightWaitNotifyExample {
final static String str = "1";
public static void main(String[] args) throws InterruptedException {
new LeftLegThread(str).start();
Thread.sleep(100);
new RightLegThread(str).start();
}
}
class LeftLegThread extends Thread {
String monitor;
public LeftLegThread(String str) {
monitor = str;
}
@Override
public void run() {
try {
makeStep();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void makeStep() throws InterruptedException {
synchronized (monitor) {
int i=0;
while (i++ < 10) {
System.out.println("Left ");
monitor.notify();
monitor.wait();
}
}
}
}
class RightLegThread extends Thread {
String monitor;
public RightLegThread(String str) {
monitor = str;
}
@Override
public void run() {
try {
makeStep();
} catch (InterruptedException e) {
}
}
private void makeStep() throws InterruptedException {
synchronized (monitor) {
while (true) {
System.out.println("Right ");
monitor.notify();
monitor.wait();
}
}
}
}
我应该把它绕成圈
但我无法想象循环条件,因为状态不变
请给出解决此问题的建议。您的程序确实具有共享状态,但您还没有编写它。您的程序在其当前实现中不会“工作”,因为通知可以由任何一个分支接收,因此您的分支可以按任何顺序运行(即,一个分支可以重复运行)。缺少的“共享状态”是“轮到谁了”。每一条腿只应在轮到它们时继续前进,然后它应将转弯传递给另一条腿并通知。您的while循环应基于当前的回合值。下面是一段代码,其中包含一些更改,说明了如何使用notify和wait in循环
public class SomeTest {
public enum Step {
Left,
Right
}
public static void main(String[] args) throws InterruptedException {
final AtomicReference<Step> currentStep = new AtomicReference<Step>(Step.Left);
new LeftLegThread(currentStep).start();
new RightLegThread(currentStep).start();
Thread.sleep(10*1000);
System.exit(0);
}
}
class LeftLegThread extends Thread {
private final AtomicReference<SomeTest.Step> currentStep;
public LeftLegThread(AtomicReference<SomeTest.Step> str) {
currentStep = str;
}
@Override
public void run() {
try {
makeStep();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void makeStep() throws InterruptedException {
synchronized (currentStep) {
while(currentStep.get().equals(SomeTest.Step.Left))
currentStep.wait();
currentStep.set(SomeTest.Step.Left);
currentStep.notify();
}
}
}
class RightLegThread extends Thread {
private final AtomicReference<SomeTest.Step> currentStep;
public RightLegThread(AtomicReference<SomeTest.Step> str) {
currentStep = str;
}
@Override
public void run() {
try {
makeStep();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void makeStep() throws InterruptedException {
synchronized (currentStep) {
while(currentStep.get().equals(SomeTest.Step.Right))
currentStep.wait();
currentStep.set(SomeTest.Step.Right);
currentStep.notify();
}
}
}
公共类测试{
公共枚举步骤{
左边
赖特
}
公共静态void main(字符串[]args)引发InterruptedException{
最终原子参考currentStep=新原子参考(步骤左);
新的LeftLegThread(currentStep).start();
新的RightLegThread(currentStep).start();
线程。睡眠(10*1000);
系统出口(0);
}
}
类LeftLegThread扩展线程{
私有最终原子参考步骤;
公共LeftLegThread(原子引用str){
currentStep=str;
}
@凌驾
公开募捐{
试一试{
makeStep();
}捕捉(中断异常e){
e、 printStackTrace();
}
}
私有void makeStep()引发InterruptedException{
已同步(currentStep){
while(currentStep.get().equals(SomeTest.Step.Left))
currentStep.wait();
currentStep.set(SomeTest.Step.Left);
currentStep.notify();
}
}
}
类RightLegThread扩展线程{
私有最终原子参考步骤;
公共RightLegThread(原子引用str){
currentStep=str;
}
@凌驾
公开募捐{
试一试{
makeStep();
}捕捉(中断异常e){
e、 printStackTrace();
}
}
私有void makeStep()引发InterruptedException{
已同步(currentStep){
while(currentStep.get().equals(SomeTest.Step.Right))
currentStep.wait();
currentStep.set(SomeTest.Step.Right);
currentStep.notify();
}
}
}
我认为正确的方法是使用两个锁。例如,右腿和左腿各有一个。左线程通知右线程,右线程通知左线程。(经过10次循环迭代后,代码将永远等待。您可能希望自己修复此问题。)
循环条件可以简单地使用枚举切换分支
public class Example {
public static void main(String[] args) throws Exception {
Object left = new Object();
Object right = new Object();
LegHolder legHolder = new LegHolder();
legHolder.leg = Leg.LEFT;
new LeftLegThread(left, right, legHolder).start();
new RightLegThread(left, right, legHolder).start();
}
}
enum Leg {
LEFT, RIGHT
}
class LegHolder {
protected volatile Leg leg;
}
class LeftLegThread extends Thread {
private final Object left;
private final Object right;
private final LegHolder holder;
public LeftLegThread(Object left, Object right, LegHolder holder) {
this.left = left;
this.right = right;
this.holder = holder;
}
@Override
public void run() {
try {
int i = 0;
while (i++ < 10) {
synchronized (left) {
System.out.println("Left ");
synchronized (right) {
holder.leg = Leg.RIGHT;
right.notify();
}
while (holder.leg != Leg.LEFT)
left.wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class RightLegThread extends Thread {
final Object left;
final Object right;
private final LegHolder holder;
public RightLegThread(Object left, Object right, LegHolder holder) {
this.left = left;
this.right = right;
this.holder = holder;
}
@Override
public void run() {
try {
synchronized (right) {
while (true) {
System.out.println("Right ");
synchronized (left) {
holder.leg = Leg.LEFT;
left.notify();
}
while (holder.leg != Leg.RIGHT)
right.wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
公共类示例{
公共静态void main(字符串[]args)引发异常{
对象左=新对象();
对象右=新对象();
LegHolder LegHolder=新的LegHolder();
legHolder.leg=leg.LEFT;
新LeftLegThread(左、右、腿支架).start();
新的RightLegThread(左、右、腿支架).start();
}
}
枚举腿{
左,右
}
阶级议员{
保护腿;
}
类LeftLegThread扩展线程{
私有最终对象左;
私人最终目的权;
私人最终立法权人;
公共LeftLegThread(对象左侧、对象右侧、腿支架){
this.left=左;
这个。右=右;
这个.holder=holder;
}
@凌驾
公开募捐{
试一试{
int i=0;
而(i++<10){
已同步(左){
系统输出打印项次(“左”);
已同步(右){
holder.leg=leg.RIGHT;
对。通知();
}
while(holder.leg!=leg.LEFT)
左。等等();
}
}
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
类RightLegThread扩展线程{
最后一个物体离开;
最终目的权;
私人最终立法权人;
public RightLegThread(对象左侧、对象右侧、腿支架){
this.left=左;
这个。右=右;
这个.holder=holder;
}
@凌驾
公开募捐{
试一试{
已同步(右){
while(true){
System.out.println(“右”);
已同步(左){
holder.leg=leg.LEFT;
左。notify();
}
while(holder.leg!=leg.RIGHT)
对,等等;
}
}
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
也就是说,一个人可能会反复尝试,但这是错误的。我使用普通显示器。请编译并启动。@gstackoverflow-多线程代码的有趣之处在于,您的测试用例可以“工作”,但仍然是完全错误的。您可以重复同一条腿,否则会出现问题,但这并不一定意味着您在测试时会看到这一点。多线程代码在遇到压力时(即在生产中)往往会显示出错误。你确定吗?请用高概率的final static String str=“1”帮助重写遇到压力情况的代码;它是共享的一部分threads@gstackoverflow-是的,我肯定。不幸的是,我不确定是否有“强制失败”的方法,因为您需要人为地延迟java处理通知的方式。这不起作用,因为您正在更改正在同步*和通知)的对象。你应该
public class Example {
public static void main(String[] args) throws Exception {
Object left = new Object();
Object right = new Object();
LegHolder legHolder = new LegHolder();
legHolder.leg = Leg.LEFT;
new LeftLegThread(left, right, legHolder).start();
new RightLegThread(left, right, legHolder).start();
}
}
enum Leg {
LEFT, RIGHT
}
class LegHolder {
protected volatile Leg leg;
}
class LeftLegThread extends Thread {
private final Object left;
private final Object right;
private final LegHolder holder;
public LeftLegThread(Object left, Object right, LegHolder holder) {
this.left = left;
this.right = right;
this.holder = holder;
}
@Override
public void run() {
try {
int i = 0;
while (i++ < 10) {
synchronized (left) {
System.out.println("Left ");
synchronized (right) {
holder.leg = Leg.RIGHT;
right.notify();
}
while (holder.leg != Leg.LEFT)
left.wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class RightLegThread extends Thread {
final Object left;
final Object right;
private final LegHolder holder;
public RightLegThread(Object left, Object right, LegHolder holder) {
this.left = left;
this.right = right;
this.holder = holder;
}
@Override
public void run() {
try {
synchronized (right) {
while (true) {
System.out.println("Right ");
synchronized (left) {
holder.leg = Leg.LEFT;
left.notify();
}
while (holder.leg != Leg.RIGHT)
right.wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}