黑马程序员——Java编程语言学习总结 – 多线程

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

多线程

进程和线程:

1)进程是静态的,其实就是指开启的一个程序;而线程是动态的,是真正执行的单元,执行的过程。其实我们平时看到的进程,是线程在执行着,因为线程是作为进程的一个单元存在的。

2)同样作为基本的执行单元,线程是划分得比进程更小的执行单位。

3)每个进程都有一段专用的内存区域。与此相反,线程却共享内存单元(包括代码和数据),通过共享的内存单元来实现数据交换、实时通信与必要的同步操作。

1、创建线程的方式:

创建方式一:继承Thread

1:定义一个类继承Thread

2:覆盖Thread中的run方法(将线程运行的代码放入run方法中)。

3:直接创建Thread的子类对象

4:调用start方法(内部调用了线程的任务(run方法));作用:启动线程,调用run方法

方式二:实现Runnable

1:定义类实现Runnable接口

2:覆盖Runnable接口中的run方法,将线程的任务代码封装到run中

3:通过Thread类创建线程对象

4、并将Runnable接口的子类对象作为Thread类的构造函数参数进行传递

作为参数传递的原因是让线程对象明确要运行的run方法所属的对象。

区别:

继承方式:线程代码放在Thread子类的run方法中

实现方式:线程存放在接口的子类run方法中;避免了单继承的局限性,建议使用。

实现方式3 利用线程池executor.newSingleThreadPloo();覆盖run()方法。

A:创建一个线程池对象,控制要创建几个线程对象。

public static ExecutorService newFixedThreadPool(intnThreads)

B:这种线程池的线程可以执行:

可以执行Runnable对象或者Callable对象代表的线程

做一个类实现Runnable接口。Callable:是带泛型的接口。

这里指定的泛型其实是call()方法的返回值类型。

C:调用如下方法即可

Future<?> submit(Runnable task)

<T> Future<T> submit(Callable<T>task)

D:我就要结束,可以吗?

可以。

 

2、线程状态:

新建:start()

临时状态:具备cpu的执行资格,但是无执行权

运行状态:具备CPU的执行权,可执行

冻结状态:通过sleep或者wait使线程不具备执行资格,需要notify唤醒,并处于临时状态。

消亡状态:run方法结束或者中断了线程,使得线程死亡。

3、多线程安全问题:

多个线程共享同一数据,当某一线程执行多条语句时,其他线程也执行进来,导致数据在某一语句上被多次修改,执行到下一语句时,导致错误数据的产生。

因素:多个线程操作共享数据;多条语句操作同一数据

解决:

原理:某一时间只让某一线程执行完操作共享数据的所有语句。

办法:使用锁机制:synchronized或lock对象

4、线程的同步:

当两个或两个以上的线程需要共享资源,他们需要某种方法来确定资源在某一刻仅被一个线程占用,达到此目的的过程叫做同步(synchronization)。

同步代码块:synchronized(对象){},将需要同步的代码放在大括号中,括号中的对象即为锁。

同步函数:放于函数上,修饰符之后,返回类型之前。

5、wait和sleep的区别:(执行权和锁区分)

wait:可指定等待的时间,不指定须由notify或notifyAll唤醒。

线程会释放执行权,且释放锁。

sleep:必须制定睡眠的时间,时间到了自动处于临时(阻塞)状态。

即使睡眠了,仍持有锁,不会释放执行权。

 

6、解决多线程安全问题代码实现:

/*

  A:同步代码块的锁对象是谁呢?

            任意对象。

 

  B:同步方法的格式及锁对象问题?

            把同步关键字加在方法上。

  

            同步方法是谁呢?

                   this

 

  C:静态方法及锁对象问题?

            静态方法的锁对象是谁呢?

                   类的字节码文件对象。

 */

 

package cn.itcast_11;

 

public class SellTicket implements Runnable {

 

       // 定义100张票

       privatestatic int tickets = 100;

 

       // 定义同一把锁

       privateObject obj = new Object();

       privateDemo d = new Demo();

 

       privateint x = 0;

       @Override

       publicvoid run() {

              while(true) {

                     if(x%2==0){

                            synchronized(SellTicket.class) {

                                   if(tickets > 0) {

                                          try{

                                                 Thread.sleep(100);

                                          }catch (InterruptedException e) {

                                                 e.printStackTrace();

                                          }

                                          System.out.println(Thread.currentThread().getName()

                                                        +"正在出售第" + (tickets--) + "张票 ");

                                   }

                            }

                     }else{

                           

                            sellTicket();

                           

                     }

                     x++;

              }

       }

      

       privatestatic synchronized void sellTicket() {

              if(tickets > 0) {

              try{

                            Thread.sleep(100);

              }catch (InterruptedException e) {

                            e.printStackTrace();

              }

              System.out.println(Thread.currentThread().getName()

                                   +"正在出售第" + (tickets--) + "张票 ");

              }

}

}

 

package cn.itcast_11;

 

public class SellTicketDemo {

       publicstatic void main(String[] args) {

              // 创建资源对象

              SellTicketst = new SellTicket();

 

              // 创建三个线程对象

              Threadt1 = new Thread(st, "窗口1");

              Threadt2 = new Thread(st, "窗口2");

              Threadt3 = new Thread(st, "窗口3");

 

              // 启动线程

              t1.start();

              t2.start();

              t3.start();

       }

}

 

 

 

7、解决线程通信问题代码实现:

/

  分析:

            资源类: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类中。

 /

 

 

 

 

public class Student {

       Stringname;

       int age;

       booleanflag; // 默认情况是没有数据,如果是true,说明有数据

}

 

public class SetThread implements Runnable {

 

       privateStudent s;

       privateint x = 0;

 

       publicSetThread(Student s) {

              this.s= s;

       }

 

       @Override

       publicvoid run() {

              while(true) {

                     synchronized(s) {

                            //判断有没有

                            if(s.flag){

                                   try{

                                          s.wait();//t1等着,释放锁

                                   }catch (InterruptedException e) {

                                          e.printStackTrace();

                                   }

                            }

                           

                            if(x % 2 == 0) {

                                   s.name= "林青霞";

                                   s.age= 27;

                            }else {

                                   s.name= "刘意";

                                   s.age= 30;

                            }

                            x++;//x=1

                           

                            //修改标记

                            s.flag= true;

                            //唤醒线程

                            s.notify();//唤醒t2,唤醒并不表示你立马可以执行,必须还得抢CPU的执行权。

                     }

                     //t1有,或者t2有

              }

       }

}

 

public class GetThread implements Runnable {

       privateStudent s;

 

       publicGetThread(Student s) {

              this.s= s;

       }

 

       @Override

       publicvoid run() {

              while(true) {

                     synchronized(s) {

                            if(!s.flag){

                                   try{

                                          s.wait();//t2就等待了。立即释放锁。将来醒过来的时候,是从这里醒过来的时候

                                   }catch (InterruptedException e) {

                                          e.printStackTrace();

                                   }

                            }

                           

                            System.out.println(s.name+ "---" + s.age);

                            //林青霞---27

                            //刘意---30

                           

                            //修改标记

                            s.flag = false;

                            //唤醒线程

                            s.notify();//唤醒t1

                     }

              }

       }

}

 

public class StudentDemo {

       publicstatic void main(String[] args) {

              //创建资源

              Students = new Student();

             

              //设置和获取的类

              SetThreadst = new SetThread(s);

              GetThreadgt = new GetThread(s);

 

              //线程类

              Threadt1 = new Thread(st);

              Threadt2 = new Thread(gt);

 

              //启动线程

              t1.start();

              t2.start();

       }

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值