多线程


多线程

一、线程概述

进程:是一个正在执行的程序,每一个进程都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元;

线程*:就是进程中的一个独立的控制单元,线程在控制进程的执行。

 

一个进程至少有一个线程;

二、创建自定义线程

1、如何在自定义代码中自定义一个线程呢?

(1)、创建线程的第一种方法:继承Thread类

    步骤:

①  、定义类继承Thread类:classDemo extends Thread{}

②  、复写Thread类中的run方法:public void run(){} 目的:将自定义的       代码存储在run方法,让线程运行。

③  、调用线程的start方法:Demod=new Demo();  d.start();作用:启动线程、调用Run方法。

 

多线程的一个特性:随机性。

      (2)、创建线程的第二种方式:实现Runnable接口

          步骤:

①  定义类实现Runnable接口:class Demoimplements Runnable{}

②  覆盖Runnable接口中的run方法:publicvoid run( ){ }

③  ‘建立子类对象:Demo  t=new Demo( );

④  通过Thread类建立线程对象,将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数:Thread t1=new Thread(t); Thread t2=new Thread(t);…….

   为什么将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数?

    因为自定义的Run方法所属的对象是Runnable接口的子类对象。所以要让线程去运行指定对象的run方法,就必须明确该run方法所属对象。

⑤  调用Thread类的start方法开启线程并调用Runnable接口子类的run方法:t1.start();   t2.start();…..

     2、两种多线程方式(实现方式和继承方式)的区别?

         实现Runnable方式:线程代码存在接口的子类的run方法中;好处:避免了单继承的局限性。开发建议使用实现方式。

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

  三、练习创建两个线程与主线程交替运行(继承方式)

class Test extends Thread
{
Test(String name)
{
    Super(name);
}
public void run()
{
    for(int x=0;x<10;x++)
    System.out.println(Thread.currentThread().getName()+“run=”+x);
}
}
class ThreadDemo
{
    public static void main(String[] args)
{
   Test t1=new Test(“one”);
   Test t2=new Test(“two”);
   T1.start();
   T2.start();
   for(int x=0;x<10;x++)
         {
            System.out.println(“main=”+x);
}
} 
}

线程都有自己默认的名称:Thread-编号从0开始。

Thread.currentThread().getName()是标准通用调用方法,此处可由this代替。

其中Thread.currentThread()是获取当前线程对象、getName()是获取线程名称。

 

四、简单的卖票程序,多个窗口同时卖票(实现方式),以及多线程的安全问题

class Test implements Runnable
{
Test (String name)
{
    super(name);
}
private int num=100;
public void run()
{
    while(true)
    {
        synchronized(obj)
        {
           if(num>0)
           {
               try{Thread.sleep(10);}catch(Exception e){}
               System.out.println(Thread.currentThread().getName()+”sale--”+num--);
           }
}
}
}
}

class TicketDemo
{
public static void main(String[] args)
{
    Test t=new Test();
    Thread t1=new Thread(t);
    Thread t2=new Thread(t);
    Thread t3=new Thread(t);
    Thread t4=new Thread(t);
    t1.start();
    t21.start();
    t3.start();
    t4.start();
}
}

1、  通过分析发现,在没有设置synchronized()时,或打印出0,-1,-2等错票

多线程的运行出现的安全问题。

问题的原因:

   当多条语句在操作同一线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来,导致共享数据的错误。

解决办法:

对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与进来。

2、  Java对于多线程的安全问题提供了专业的解决方式,就是:同步代码块

同步代码块格式:synchronized(对象){需要被同步的代码}

 

如本例,obj对象就如同锁,持有锁的线程可以在同步中执行,没有持有锁的线程即使获得cpu的执行权也进不来,因为没有锁。(火车上厕所的例子)

 

同步的前提:1、必须要有两个或两个以上的线程;2、必须是多个线程使用同一个锁。

必须保证同步中只能有一个线程在运行。

好处:解决了多线程的安全问题

弊端:多线程需要判断锁,较为消耗资源。

五、同步函数的创建使用

例题:需求:银行有一个金库,有两个储户分别存300元分三次存每次100元

class Cus implements Runnable
{
    private Bank b=new Bank();
public viod run()
{
    for(int x;x<3;x++)
      b.add(100);
}
}
class Bank
{
private int sum;
public synchronized void add(int n)   //把同步代码块放在函数上,实现同步函数
{
    sum=sum+n;
    try{Thread.sleep(10);}catch(Exception e){}
    System.out.println(Thread.currentThread().getName()+”sum=”+sum);
}
}
class BankDemo
{
public static void main(String[] args)
{
    Cus c=new Cus();
    Thread c1=new Thread(c);
    Thread c2=new Thread(c);
    c1.start();
    c2.start();
}
}

1、  目的:改程序是否有安全问题,如果有如何解决?

如何找到问题?

1、  明确哪些代码是多线程代码

2、  明确共享数据

3、  明确多线程代码中哪些语句是操作共享数据的

2、  同步函数用的是哪一个锁?

函数需要被对象调用,那么函数有一个所属对象引用,就是this。

3、  同步函数被静态static修饰后,同步函数的锁是什么?

静态进内存时,内存中没有本类对象,但是一定有该类对应字节码文件对象

类名.class    该对象的类型是class

因此,静态同步方法时,使用的锁是该方法所在类的字节码文件对象类名.class

class Ticket implements Thread
{
 private static int tick=100;
 boolean flag=true;
 public void run()
 {
  if(flag)
  {
   while(true)
   {
synchronized(Ticket.class)//同步函数被静态修饰后,传入的对象是类名.class
{
 if(tick>0)
 {
  try{Thread,.sleep(10);}catch(Exception e){}
  System.out.println(Thread.currentThread().getName()+” coad:”+tick--);
}
}
}
}
  else
   while(true)
    show();
}
public static synchronized void show()
{
 if(tick>0)
 { 
  try{Thread.sleep(10);}catch(Exception e){}
  System.out.println(Thread.currentThread().getName()+”show:”+tick--);
}
}
}
class StaticTicketDemo
{
 public static void main(String[] args)
{
 Ticket t=new Ticket();
 Thread t1=new Thread(t);
 Thread t2=new Thread(t);
 t1.start();
 try{Thread,sleep(10);}catch(Exception e){}
t.flag=false;
 t2.start();
}
}

六、单例设计两种模式中懒汉式在同步代码快中的应用

前瞻:

饿汉式:

class Single

{

 private static Single s=new Single();

 private Single(){}

 public static Single getInstance()

 {

  return s;

}

}

*懒汉式:

class Single

{

 private static Single s=null;

 private Single(){}

 public static Single getInstance()

 {

 if(s==null)

  {

  synchronized(Single.class)

   {

if(s==null)

s=new Single();

}

}

return s;

}

}

 

七、死锁,请写出一个死锁程序

四路,互相内嵌同步代码块

class Test implements Runnable
{
 private Boolean flag;
 Test(Boolean flag)
 {
  this.flag=flag;
}
public void run()
{
 if(flag)
 {
  while(true)
  {
   synchronized(MyLoka)
   {
    System.out.println(“if locka”);
    synchronized(MyLockb)
      System.out.println(“if lockb”);
}
}
}
else
{ 
 while(true)
 { 
  synchronized(MyLockb)
  {
   System.out.println(“else lockb”);
   synronized(MyLocka)
   System.out.println(“else locka”);
}
}
}
}
}
class MyLock
{
  static Object locka=new Object();
  static Object lockb=new Object();
}
class DeadLock
{
 public stativ void main(String[] args)
 {
   Thread t1=new Thread(new Test(true));
   Thread t2=new Thread(new Test(flase));
   t1.start();
   t2.start();	
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

leefeng.top

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值