首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >预Java 5线程

预Java 5线程
EN

Code Review用户
提问于 2014-04-12 23:51:58
回答 1查看 165关注 0票数 4

我想在Java 5之前修改Java线程的基本原理,这样我就可以理解Java 5和更高版本的改进。

我从一个自定义集合开始,需要帮助:

  1. 我做错了/严重忽视的事情
  2. 如何使它变得更好
  3. 建议替代实施,如果有的话
  4. 使用kill变量的正确位置是哪个?它是在线程中还是在集合中,就像我做的那样?
代码语言:javascript
复制
public class ThreadCreation {

    public static void main(String[] args) {
        MyCollection coll = new MyCollection();
        coll.kill = false;

        RemoveCollClass t2 = new RemoveCollClass();
        t2.setName("Thread2");
        t2.coll = coll;
        t2.start();

        AddCollClass t1 = new AddCollClass();
        t1.setName("Thread1");
        t1.coll = coll;
        t1.start();

        RemoveCollClass t3 = new RemoveCollClass();
        t3.setName("Thread3");
        t3.coll = coll;
        t3.start();

        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        coll.kill = true;
    }

    static class AddCollClass extends Thread {

        volatile MyCollection coll;
        int count = 0;

        @Override
        public void run() {

            while (!coll.kill) {
                System.out.println(Thread.currentThread().getName()
                        + " --> AddCollClass Attempt -->" + count);
                coll.add();
                count++;
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

        }
    }

    static class RemoveCollClass extends Thread {

        volatile MyCollection coll;
        int count = 0;

        @Override
        public void run() {
            // System.out.println("ThreadClass is running ");

            while (!coll.kill) {
                System.out.println(Thread.currentThread().getName()
                        + " -->RemoveCollClass Attempt -->" + count);
                coll.remove();
                count++;

            }

        }
    }

    static class MyCollection {
        Stack<String> container = new Stack<String>();

        int maxSize = 5;
        volatile boolean kill = false;

        public synchronized boolean isFull() {
            if (container.size() >= maxSize)
                return true;
            else
                return false;
        }

        public synchronized boolean isEmpty() {
            if (container.size() <= 0)
                return true;
            else
                return false;
        }

        public synchronized void add() {

            if (isFull()) {
                try {
                    System.out.println("wait triggered on-->"
                            + Thread.currentThread().getName());
                    wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    notify();
                }
            }
            if (!isFull()) {
                container.add(Thread.currentThread().getName());
                System.out.println(" Add Completed by "
                        + Thread.currentThread().getName());
                notify();
            }

        }

        public synchronized void remove() {

            if (isEmpty()) {
                try {
                    System.out.println("wait triggered on-->"
                            + Thread.currentThread().getName());
                    wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    notify();
                }
            }
            if (!isEmpty()) {
                container.pop();
                System.out.println(" Remove Completed by "
                        + Thread.currentThread().getName());
            }

        }
    }

}
EN

回答 1

Code Review用户

发布于 2014-04-13 03:54:20

不管您使用的是哪个版本的Java,在Java中使用最佳实践线程时,有几件事情是“错误的”。

The Big

  • 避免易失性,除非您别无选择(特别是在Java5中的预Java5 5中,以及稍后的易失性关键字引入了更可预测的行为)。
  • 在这个程序中,您可以选择,并且不需要易失性。
  • 避免扩展线程。相反,扩展Runnable并使用runnable作为线程构造函数。
  • 永远不要在方法上同步,除非你真的,真的必须,而且你也不必同步。

Synchronization

通过同步这些方法,这意味着任何人都可以破坏您的程序。如果一个人决定在他们的程序中使用您的类作为某种构造,那么他们会:

代码语言:javascript
复制
private final MyCollection mycoll = new MyCollection();

public void methodABC() {
    synchronized(mycoll) {
        // do a bunch of stuff
    }
}

突然你的同步结束了..。死锁就会发生。见这个堆栈溢出的讨论

既然您的MyCollection类有collection堆栈实例,请使用它作为监视器锁……(并让它成为私人决赛:

代码语言:javascript
复制
static class MyCollection {
    private final Stack<String> container = new Stack<String>();

    int maxSize = 5;
    volatile boolean kill = false;

    public boolean isFull() {
        synchronized (container) {
            return container.size() >= maxSize;
        }
    }

另外,您应该使用notifyAll(),而不仅仅是notify()。尤其是当您使用方法/实例同步时,因为您类之外的任何人都可能得到通知,如果他们阻止您的类.您可能最终会通知其他不属于您类的线程.实际上,那里有一个真正的bug:

错误:不正确的通知.

如果两个线程从一个完整的集合中移除一个项,而另外两个线程正在等待空间将其放入.然后两个移除线程都可以通知相同的添加线程,而第二个添加线程可能仍然在等待,即使通过有空间.

使用notifyAll();

易挥发

在Java5被打破之前是不稳定的。不要用它。

在持有锁时,您的任何方法都不会阻塞(它们都是释放锁的“等待”)。因此,你的锁保持时间真的很短。

因此,没有理由将kill分离为易失性。只需有一个killisKilled方法。

当使用你可以理解这篇文章时,可以使用易失性

可运行

所有的“线程”类都应该是可运行的。

它们应该有私有的最终变量,而根本不具有易失性。例如,这个类:

静态类RemoveCollClass扩展线程{易失性MyCollection coll;int count = 0;@Override (){ // System.out.println("ThreadClass正在运行");而(!coll.kill) {ThreadClass+ -->RemoveCollClass尝试->“+count”;coll.remove();count++;}}

看起来应该是:

代码语言:javascript
复制
static class RemoveCollClass implements Runnable {

    private final MyCollection coll;
    int count = 0;

    public RemoveCollClass(MyCollection coll) {
        super();
        this.coll = coll;
    }


    public void run() {
        // System.out.println("ThreadClass is running ");

        while (!coll.isKilled()) {
            System.out.println(Thread.currentThread().getName()
                    + " -->RemoveCollClass Attempt -->" + count);
            coll.remove();
            count++;

        }

    }
}

然后,使用Runnable作为线程构造函数:

代码语言:javascript
复制
    RemoveCollClass rcc2 = new RemoveCollClass(coll);
    Thread t2 = new Thread(rcc2, "Thread2");
    t2.setDaemon(true);
    t2.start();

小事情:

  • 简化您的逻辑:公共同步布尔isEmpty() { if (container.size() <= 0)返回真;否则返回false;}此代码可以简单地为:公共同步布尔值isFull() {返回container.size() >= maxSize;}公共同步布尔isEmpty() {返回container.empty();}
    • //TODO在渔获区..。为什么?

代码语言:javascript
复制
              } catch (InterruptedException e) {                     // TODO Auto-generated catch block                     e.printStackTrace();                     notify();                 }    
代码语言:javascript
复制
- Don't use i-liner if/else blocks. They lead to bugs:
代码语言:javascript
复制
      if (container.size() <= 0)             return true;  
票数 4
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/47030

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档