——JAVASE-线程

一、线程的概念
进程:是一个正在执行中的程序,每一个进程执行都有一个执行顺序,该顺序是一个执行路径或者叫一个控制单元
线程:线程是程序执行的一条路径, 或者叫做进程一个独立的控制单元,一个进程中可以包含多条线程,线程在控制着进程的执行。
二、自定义新线程
1、创建线程的第一种方式:继承Thread类。
步骤:
(1)、定义类继承Thread。
(2)、复写Thread类中的run方法。
目的:将自定义代码存储在run方法。让线程运行。
(3)、调用线程的start方法,
该方法两个作用:启动线程,调用run方法。

//1,定义类继承Thread
class Demo extends Thread 
{
    public void run()//2,重写run方法
    { //3,将要执行的代码,写在run方法中
        for(int x=0; x<60; x++)
            System.out.println("demo run----"+x);
    }
}
class ThreadDemo 
{
    public static void main(String[] args) 
    {
        Demo d = new Demo();//4,创建自定义类的对象。
        d.start();//5,开启线程并执行该线程的run方法。
        //d.run();//仅仅是对象调用方法。而线程创建了,并没有运行。
        for(int x=0; x<60; x++)
        System.out.println("Hello World!--"+x);
        }
}

2、创建线程的第二种方式:实现Runable接口
步骤:
(1)、定义类实现Runnable接口
(2)、覆盖Runnable接口中的run方法。将线程要运行的代码存放在该run方法中。
(3)、通过Thread类建立线程对象。
(4)、将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
原因:自定义的run方法所属的对象是Runnable接口的子类对象。
所以要让线程去实现指定对象的run方法。就必须明确该run方法所属对象。
Thread(Runnable target) 分配新的 Thread 对象。
(5)、调用Thread类的start方法开启线程,内部会自动调用Runnable接口子类的run 方法。

//1,自定义类实现Runnable接口
class Ticket implements Runnable
{
    private  int tick = 100;
    public void run() //2,重写run方法
    { //3,将要执行的代码,写在run方法中
        while(true)
        {
            if(tick>0)
            {
System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--);
            }
        }
    }
}
class  TicketDemo
{
    public static void main(String[] args) 
    {
        Ticket t = new Ticket();//4,创建自定义类对象
        Thread t1 = new Thread(t);//5,将其当作参数传递给Thread的构造函数
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        Thread t4 = new Thread(t);
        t1.start(); //6,开启线程
        t2.start();
        t3.start();
        t4.start();
      for(int i = 0; i < 3000; i++)
       {
            System.out.println("bb");
        }
    }
}

3、两种方式区别
(1)、继承Thread:线程代码存放Thread子类run方法中。
实现Runnable,线程代码存在接口的子类的run方法。
(2)、继承Thread
好处是:可以直接使用Thread类中的方法,代码简单
弊端是:如果已经有了父类,就不能用这种方法(JAVA不支持多继承的原因)
实现Runnable接口
好处是:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,而且接口是可以多实现的
弊端是:不能直接使用Thread中的方法需要先获取到线程对象后,才能得到Thread的方法,代码复杂
三、Thread类常用方法
public void start()使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
public final String getName() 获取线程的名称。
public final void setName(String name) 设置线程名称,通过Thread构造函数也可以实现
public static Thread currentThread()返回对当前正在执行的线程对象的引用。
public final void setDaemon(boolean on)将该线程标记为守护线程或用户线程。
该方法必须在启动线程前调用。
public static void yield()暂停当前正在执行的线程对象,并执行其他线程。
public static void sleep(long millis)在指定的毫秒数内让当前正在执行的线程休眠
public final void join()等待该线程终止,可用来临时加入线程
public final void setPriority(int newPriority)设置线程的优先级
public String toString()返回该线程的字符串表示形式,包括线程名称、优先级和线程组。

/*
join:
当A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完,A才会执行。join可以用来临时加入线程执行。
*/
class Demo implements Runnable
{
    public void run()
    {
        for(int x=0; x<70; x++)
        {
            System.out.println(Thread.currentThread().toString()+"....."+x);
            Thread.yield();
        }
    }
}
class  JoinDemo
{
    public static void main(String[] args) throws Exception
    {
        Demo d = new Demo();
        Thread t1 = new Thread(d);
        Thread t2 = new Thread(d);
        t1.start();
        //t1.setPriority(Thread.MAX_PRIORITY);
        t2.start();
        t1.join();
        for(int x=0; x<80; x++)
        {    System.out.println((Thread.currentThread()+"..."+getName()+"run..."+x);
        }
        System.out.println("over");
    }
}

四、线程之间的同步
1、什么情况下需要同步
当多线程并发, 有多段代码同时执行时, 我们希望某一段代码执行的过程中CPU不要切换到其他线程工作. 这时就需要同步。如果两段代码是同步的, 那么同一时间只能执行一段, 在一段代码没执行结束之前, 不会执行另外一段代码。
2、同步函数
使用synchronized关键字修饰一个方法, 该方法中所有的代码都是同步的

class Bank
{
    private int sum;
    public synchronized void add(int n)
    {
        {
            sum = sum + n;
            //try{Thread.sleep(10);}catch(Exception e){}
            System.out.println("sum="+sum);
        }
    }
}
class Cus implements Runnable
{
    private Bank b = new Bank();
    public void run()
    {       
        for(int x=0; x<3; x++)
        {
            b.add(100);
        }
    }
}

3、同步代码块
使用synchronized关键字加上一个锁对象来定义一段代码, 这就叫同步代码块
多个同步代码块如果使用相同的锁对象, 那么他们就是同步的

class Ticket implements Runnable
{
   private  int tick = 1000;
    Object obj = new Object();
    public void run()
    {
        while(true)
        {
            synchronized(obj)
            {
                if(tick>0)
                {
                    //try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--);
                }
            }
        }
    }
}
class  TicketDemo2
{
    public static void main(String[] args) 
    {   Ticket t = new Ticket();
        Thread t1 = new Thread(t).start();
        Thread t2 = new Thread(t).start();
        }
}

4、锁
同步函数使用的锁是this;
静态同步函数使用的锁是该方法所在类的字节码文件对象;类名.class;
同步代码块使用的锁是任意的
5、死锁问题
多线程同步的时候, 如果同步代码嵌套, 使用相同锁, 就有可能出现死锁,尽量不要嵌套使用

private static String s1 = "筷子左";
private static String s2 = "筷子右";
public static void main(String[] args) {
    new Thread() {
        public void run() {
          while(true) {
            synchronized(s1) {
              System.out.println(getName() + "...拿到" + s1 + "等待" + s2);
                synchronized(s2) {
                     System.out.println(getName() + "...拿到" + s2 + "开吃");
                    }
                }
            }
        }
    }.start();

    new Thread() {
        public void run() {
            while(true) {
             synchronized(s2) {
              System.out.println(getName() + "...拿到" + s2 + "等待" + s1);
                synchronized(s1) {
                   System.out.println(getName() + "...拿到" + s1 + "开吃");
                    }
                }
            }
        }
    }.start();
}

五、单例设计模式
单例设计模式:保证类在内存中只有一个对象。
如何保证类在内存中只有一个对象呢?
(1)控制类的创建,不让其他类来创建本类的对象。private私有化构造函数
(2)在本类中定义一个本类的对象。Singleton s;
(3)提供公共的访问方式。 public static Singleton getInstance(){return s}
单例写法两种:

//饿汉式,开发时使用这种
/*
class Single
{
    private static final 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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值