基础 多线程 Thread synchronize 单例设计模式 死锁

多线程

  • 进程
  • 线程 (例:FlashGet
  • 多线程存在的意义
  • 线程的创建方式
  • 多线程的特性

创建线程的第一种方式:继承Thread类
步骤:

  1. 定义类继承Thread
  2. 复写Thread类中的run方法
    • 目的:将自定义的代码存储在run方法中,让线程运行
  3. 调用线程的start方法
    • 该方法两个作用:启动线程,调用run方法
package 多线程.继承Thread;

class Demo extends Thread//继承Thread
{
    public void run()//复写run方法
    {
        for(int x=0;x<100;x++)
        {
            System.out.println("Demo run--"+x);
        }
    }
}

public class ThreadDemo {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Demo d=new Demo();//创建对象
        d.start();//启动线程
        for(int x=0;x<100;x++)
        {
            System.out.println("Main--"+x);
        }
    }

}

线程都有默认名称
Thread-编号 该编号从0开始
通过this.getName()获取当前线程名称
通过 线程对象.setName(String name)可以设置线程名称

通过构造函数设置线程名称

class Demo extends Thread
{
    public Demo()//默认构造函数
    {
        super();
    }
    public Demo(String name)//通过name参数构造带名称的线程
    {
        super(name);
    }
    public void run()
    {
        for(int x=0;x<100;x++)
        {
            System.out.println(this.getName()+"--"+x);
        }
    }
}

获取当前线程对象
static Thread.currentThread()

创建线程的第二种方法:实现Runnable接口

  1. 定义类实现Runnable接口
  2. 覆盖Runnable接口中的run方法
  3. 通过Thread类建立线程对象
  4. 将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
  5. 调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。
class RunDemo implements Runnable
{
    private int tick=100;
    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(true)
        {
            if(tick>0)
            {
                System.out.println(Thread.currentThread().getName()+" "+tick--);
            }
            else
                break;
        }
    }

}

public class RunnableDemo {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        RunDemo rd=new RunDemo();
        Thread t1=new Thread(rd);
        Thread t2=new Thread(rd);
        Thread t3=new Thread(rd);
        Thread t4=new Thread(rd);
        t1.start();
        t2.start();
        t3.start();
        t4.start();

    }

}

实现方式好处:避免了单继承的局限性。
在定义线程时,建立使用实现方式。

两种方式区别:
继承Thread:线程代码存放在Thread子类run方法中。
实现Runnable,线程代码存放在接口的子类的run方法。

多线程安全问题

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

使用同步代码块。

synchronized(对象)
{
需要被同步的代码
}

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

好处:解决了多线程的安全问题。
弊端:多个线程需要判断锁,较为消耗资源

使用同步函数:

public synchronized void add(int n)
    {
        //synchronized(obj)
        //{
            sum=sum+n;
            System.out.println("sum="+sum);
        //}
    }

同步函数的锁是this

class Ticket implements Runnable//创建类,实现接口Runnable,实现run方法
{
    private int tick=100;
    public boolean flag=true;
    @Override
    public void run() {
        // TODO Auto-generated method stub
        if(flag)
        {
            while(true){
                synchronized(this)//使用this对象作为锁
                {
                    if(tick>0)
                    {
                        try
                        {
                            Thread.sleep(2);
                        }
                        catch(Exception e){ }
                        System.out.println(Thread.currentThread().getName()+" "+tick--);

                    }
                    else
                        break;
                }
            }
        }
        else
            while(show()){      }


    }
    public synchronized boolean show()//同步函数的锁是this
    {
        if(tick>0)
        {
            try
            {
                Thread.sleep(2);
            }
            catch(Exception e){ }
            System.out.println(Thread.currentThread().getName()+" "+tick--);
            return true;
        }
        else
            return false;
    }

}

public class ThisLockDemo {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Ticket t=new Ticket();//创建run方法的对象
        Thread t1=new Thread(t);//创建线程1,传递Runnable接口的实现类的对象
        Thread t2=new Thread(t);//创建线程2,传递Runnable接口的实现类的对象

        t1.start();
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        t.flag=false;//t1执行同步代码块
        t2.start();//t2执行同步函数
//t1,t2用同一个锁this,所以不会同时执行,也就不会发生对同一个变量同时操作的危险。

    }

}

静态同步函数的锁是 Class对象

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

单例设计模式 懒汉式

package 多线程.懒汉式;

class Single
{
    private static Single s;//声明静态的Single类对象s,保证只有一个s对象
    private int x;
    private Single(){}//构造方法私有化,禁止创建多个对象
    public static Single getInstance()//只能通过静态方法getInstance获取Single类的实例
    {
        if(s==null)//第一重判断
        {
            synchronized(Single.class){//加同步锁,防止多个线程进入
                if(s==null)//第二重判断,保证只有一个实例对象
                    s=new Single();//如果没有创建对象实例,就创建实例

            }
        }
        return s;//返回Single类的对象引用
    }

    public  void show()
    {
        while(true)
        {
            synchronized(this)//加入同步,防止多个线程操作共享数据x时发生同时进入代码操作。
            {
                if(x<100)
                {
                    try
                    {
                        Thread.sleep(1);
                    }
                    catch(Exception e)
                    {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+":"+x++);

                }
                else
                    break;
            }
        }
    }

}

class MyThread extends Thread//继承Thread类覆盖run方法实现自己的线程功能
{
    public void run()
    {
        Single s=Single.getInstance();//线程获取对象
        s.show();//线程使用对象方法
    }
}

public class SingleDemo {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        MyThread t1=new MyThread();//创建线程1
        MyThread t2=new MyThread();//创建线程2
        t1.start();//启动线程1
        t2.start();//启动线程2
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值