同步机制以及线程组、线程池

         一: 进程同步是进程之间直接的相互作用,是合作进程间有意识的行为,典型的例子是公共汽车上司机与售票员的合作。只有当售票员关门之后司机才能启动车辆,只有司机停车之后售票员才能开车门。司机和售票员的行动需要一定的协调。同样地,两个进程之间有时也有这样的依赖关系,因此我们也要有一定的同步机制保证它们的执行次序。 

            问题一:wait(),notify(),notifyAll() 这些方法为什么会定义在Object类中呢?

             答:这些方法好像就属于线程的方法,但是Thread类中并没有这些方法,多线程中同步锁对象:任意的Java类

  这些方法都和锁对象有关系,所以定义在Object类


           问题二:wait()和sleep(long times) 的区别?

           答:对于sleep()方法,我们首先要知道该方法是属于Thread类中的

         sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当      指定的时间到了又会自动恢复运行状态。在调用sleep()方法的过程中,线程不会释放对象锁。

          而wait()方法,则是属于Object类中的。 当调用wait()方法的时候,线程会放弃对象锁,进入等待此      对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备

     获取对象锁进入运行状态。


  问题三:  同步机制(同步代码块/同步方法) 此时出现了非线程安全问题,因为两个线程同时访问一个没有同步         的方法,如果这两个线程同时操作业务对象中的实例变量,就有可能出现非线程安全问题。

        答:解决方案在开发中,使用synchronized(Lock锁也可以)同步代码块将多条语句对共享数据的操作包起来!  只需要在       public void run()前面加synchronized关键词即可。

       :关于Lock对象和synchronized关键字的选择: 

        a.最好两个都不用,使用一种java.util.concurrent包提供的机制, 
            能够帮助用户处理所有与锁相关的代码。 
        b.如果synchronized关键字能满足用户的需求,就用synchronized,因为它能简化代码 
        c.如果需要更高级的功能,就用ReentrantLock类,此时要注意及时释放锁,
         否则会出现死锁,通常在finally代码释放锁 。  
             ReenreantLock类的常用方法有:
          ReentrantLock() : 创建一个ReentrantLock实例 
          lock() : 获得锁 
          unlock() : 释放锁 


二: 线程组:程组表示一个线程的集合。此外,线程组也可以包含其他线程组。

     线程组存在的意义,首要原因是安全。
    java默认创建的线程都是属于系统线程组,而同一个线程组的线程是可以相互修改对方的数据的。
    但如果在不同的线程组中,那么就不能“跨线程组”修改数据,可以从一定程度上保证数据安全.

 

   【示例程序】

public static void main(String[] args) {

//获取线程组的名称

           // method1();

//如何给多个线程设置一个线程组名称呢?
method2();
}


private static void method2() {
// public ThreadGroup(String name)构造一个新线程组
ThreadGroup tg = new ThreadGroup("main-新的线程组") ;

MyThread my = new MyThread() ;

// Thread(ThreadGroup group, Runnable target, String name) 
Thread t1 = new Thread(tg, my, "线程1") ;
Thread t2 = new Thread(tg, my, "线程2") ;

//直接获取线程组名称
System.out.println(t1.getThreadGroup().getName());
System.out.println(t2.getThreadGroup().getName());
}


private static void method1() {
MyThread my = new MyThread() ;

//创建线程类对象

Thread t1 = new Thread(my, "线程1") ;
Thread t2 = new Thread(my, "线程2") ;

//public final ThreadGroup getThreadGroup()返回该线程所属的线程组
ThreadGroup tg1 = t1.getThreadGroup() ;
ThreadGroup tg2 = t2.getThreadGroup() ;

//public final String getName():返回线程组的名称
System.out.println(tg1.getName()); //main
System.out.println(tg2.getName());//main

//所有的线程它默认的线程组名称:main(主线程)
System.out.println(Thread.currentThread().getThreadGroup().getName());//main
}
}

 

三: 线程池(某个线程执行完毕,反复利用线程对象

        线程池:多个线程执行完毕,它会重新回到线程池中,等待被利用,不会变成垃圾!

     线程池存在的意义,首要作用是效率。
    线程的创建和结束都需要耗费一定的系统时间(特别是创建),不停创建和删除线程会浪费大量的时间。所     以, 在创建出一条线程并使其在执行 任务后不结束,而是使其进入休眠状态,在需要用时再唤醒,那么 就     可以节省一定的时间。
    如果这样的线程比较多,那么就可以使用线程池来进行管理。保证效率。

  和线程池有关的类
       类 Executors: 一种工厂类
       方法:
  和线程池的创建有关系
  public static ExecutorService newFixedThreadPool(int nThreads)
  创建一个可重用固定线程数的线程池
 
        ExecutorService:可以执行异步任务
创建一个线程池,执行接口中的方法
  提交:Future<?> submit(Runnable task)
  <T> Future<T> submit(Callable<T> task)提交一个返回值的任务用于执行,返回一个表示任务的                         未决结果的 Future
                       Future:接口(Future 表示异步计算的结果)

  线程池调用完毕可以关闭的

  void shutdown():关闭之前,会提交刚才的任务

【示例程序】:主程序分别计算每个线程的求和! 

 

                package org.westos_15;
                import java.util.concurrent.ExecutionException;
                import java.util.concurrent.ExecutorService;
                import java.util.concurrent.Executors;
                import java.util.concurrent.Future;

                public class ExecutorsTest {

        public static void main(String[] args) throws InterruptedException,ExecutionException {

//创建线程池对象
ExecutorService pool = Executors.newFixedThreadPool(2) ;

//提交任务
Future<Integer> f1 = pool.submit(new MyCallable(100)) ;
Future<Integer> f2 = pool.submit(new MyCallable(200)) ;

//V get():获取结果
Integer i1 = f1.get() ;
Integer i2 = f2.get() ;

System.out.println(i1);
System.out.println(i2);

//关闭线程池
pool.shutdown();
}

}

子程序

            package org.westos_15;
            import java.util.concurrent.Callable;
            public class MyCallable implements Callable<Integer> {

         //定义个变量
        private int number ;


    public MyCallable(int number) {
this.number = number;
    }

    @Override
    public Integer call() throws Exception {
     //定义最终结果变量
int sum = 0 ;
for(int x =1 ; x <=number ; x ++) {
sum +=x ;
}
return sum;
}
}

 
四:线程组和线程池共有的特点:
    1,都是管理一定数量的线程
    2,都可以对线程进行控制---包括休眠,唤醒,结束,创建,中断(暂停)--但并不一定包含全部这些操作。

猜你喜欢

转载自blog.csdn.net/qq_41141896/article/details/80498848