百木园-与人分享,
就是让自己快乐。

多线程(线程组【ThreadGroup】)

线程组: 把多个线程组合到一起。
* 它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。

package cn.itcast_06;

public class MyRunnable implements Runnable {

    @Override
    public void run() {
        for (int x = 0; x < 100; x++) {
            System.out.println(Thread.currentThread().getName() + \":\" + x);
        }
    }

}
package cn.itcast_06;

/*
 * 线程组: 把多个线程组合到一起。
 * 它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
 */
public class ThreadGroupDemo {
    public static void main(String[] args) {
        // method1();

        // 我们如何修改线程所在的组呢?
        // 创建一个线程组
        // 创建其他线程的时候,把其他线程的组指定为我们自己新建线程组
        method2();

        // t1.start();
        // t2.start();
    }

    private static void method2() {
        // ThreadGroup(String name)
        //public ThreadGroup(String name)构造一个新线程组
        //name - 新线程组的名称。
        ThreadGroup tg = new ThreadGroup(\"这是一个新的组\");

        MyRunnable my = new MyRunnable();
        // Thread(ThreadGroup group, Runnable target, String name)
        //将线程t1放到线程组tg中并给线程分别取名为\"林青霞\",\"刘意\"
        Thread t1 = new Thread(tg, my, \"林青霞\");
        Thread t2 = new Thread(tg, my, \"刘意\");
        
        //public final ThreadGroup getThreadGroup()返回该线程所属的线程组并获取此线程组的名称
        System.out.println(t1.getThreadGroup().getName());
        System.out.println(t2.getThreadGroup().getName());
        
        //通过组名称设置后台线程,表示该组的线程都是后台线程
        tg.setDaemon(true);
    }

    private static void method1() {
        MyRunnable my = new MyRunnable();
        //public Thread(Runnable target,String name)分配新的 Thread 对象
        //target - 其 run 方法被调用的对象。
        //name - 新线程的名称
        Thread t1 = new Thread(my, \"林青霞\");
        Thread t2 = new Thread(my, \"刘意\");
        // 我不知道他们属于那个线程组,我想知道,怎么办
        //public final ThreadGroup getThreadGroup()返回该线程所属的线程组
        // 线程类里面的方法:public final ThreadGroup getThreadGroup()
        ThreadGroup tg1 = t1.getThreadGroup();
        ThreadGroup tg2 = t2.getThreadGroup();
        // 线程组里面的方法:public final String getName()
        String name1 = tg1.getName();
        String name2 = tg2.getName();
        System.out.println(name1);
        System.out.println(name2);
        // 通过结果我们知道了:线程默认情况下属于main线程组
        // 通过下面的测试,你应该能够看到,默任情况下,所有的线程都属于同一个组
        System.out.println(Thread.currentThread().getThreadGroup().getName());
    }
}

 生产者和消费者之等待唤醒机制的代码优化

package cn.itcast_07;

public class Student {
    private String name;
    private int age;
    private boolean flag; // 默认情况是没有数据,如果是true,说明有数据

    public synchronized void set(String name, int age) {
        // 如果有数据,就等待
        if (this.flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // 设置数据
        this.name = name;
        this.age = age;

        // 修改标记
        this.flag = true;
//唤醒等待的单个线程
this.notify(); } public synchronized void get() { // 如果没有数据,就等待 if (!this.flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 获取数据 System.out.println(this.name + \"---\" + this.age); // 修改标记 this.flag = false; this.notify(); } }

 

 线程实现类---设置和获取信息

package cn.itcast_07;

public class SetThread implements Runnable {

    private Student s;
    private int x = 0;

    public SetThread(Student s) {
        this.s = s;
    }

    @Override
    public void run() {
        while (true) {
            if (x % 2 == 0) {
                s.set(\"林青霞\", 27);
            } else {
                s.set(\"刘意\", 30);
            }
            x++;
        }
    }
}

package cn.itcast_07;

public class GetThread implements Runnable {
    private Student s;

    public GetThread(Student s) {
        this.s = s;
    }

    @Override
    public void run() {
        while (true) {
            s.get();
        }
    }
}

 

 测试

 

package cn.itcast_07;

/*
 * 分析:
 *         资源类:Student    
 *         设置学生数据:SetThread(生产者)
 *         获取学生数据:GetThread(消费者)
 *         测试类:StudentDemo
 * 
 * 问题1:按照思路写代码,发现数据每次都是:null---0
 * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个
 * 如何实现呢?
 *         在外界把这个数据创建出来,通过构造方法传递给其他的类。
 * 
 * 问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题
 *         A:同一个数据出现多次
 *         B:姓名和年龄不匹配
 * 原因:
 *         A:同一个数据出现多次
 *             CPU的一点点时间片的执行权,就足够你执行很多次。
 *         B:姓名和年龄不匹配
 *             线程运行的随机性
 * 线程安全问题:
 *         A:是否是多线程环境        是
 *         B:是否有共享数据        是
 *         C:是否有多条语句操作共享数据    是
 * 解决方案:
 *         加锁。
 *         注意:
 *             A:不同种类的线程都要加锁。
 *             B:不同种类的线程加的锁必须是同一把。
 * 
 * 问题3:虽然数据安全了,但是呢,一次一大片不好看,我就想依次的一次一个输出。
 * 如何实现呢?
 *         通过Java提供的等待唤醒机制解决。
 * 
 * 等待唤醒:
 *         Object类中提供了三个方法:
 *             wait():等待
 *             notify():唤醒单个线程
 *             notifyAll():唤醒所有线程
 *         为什么这些方法不定义在Thread类中呢?
 *             这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。
 *             所以,这些方法必须定义在Object类中。
 * 
 * 最终版代码中:
 *         把Student的成员变量给私有的了。
 *         把设置和获取的操作给封装成了功能,并加了同步。
 *         设置或者获取的线程里面只需要调用方法即可。
 */
public class StudentDemo {
    public static void main(String[] args) {
        //创建资源
        Student s = new Student();
        
        //设置和获取的类
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);

        //线程类
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);

        //启动线程
        t1.start();
        t2.start();
    }
}

 


来源:https://www.cnblogs.com/ztg-java-xuexi/p/16104092.html
本站部分图文来源于网络,如有侵权请联系删除。

未经允许不得转载:百木园 » 多线程(线程组【ThreadGroup】)

相关推荐

  • 暂无文章