JAVA线程学习心得

JAVA线程

笔者主要从以下三个角度,总结了对java线程基本内容的学习心得,希望对大家有所帮助。才疏学浅,如有纰漏,还望大家指出。


***1.什么是线程?
2.为什么要使用线程?
3.怎么实现线程?*


什么是线程?

不去细讲线程的定义,就拿一个形象的例子来比喻一下什么是线程。假设你现在只有要听写单词,听写单词需要用你的大脑控制你的耳朵去听、眼睛去看、手去写、大脑皮层去找单词的拼写,这个时候就相当于启动了多线程。只有这个“组合动作”帮助你的完成你的听写的整个过程。线程就是这样的存在,简单的说,就是多线并发操作。

官方一点的解释: 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。。

为什么要使用线程?

这个问题问的好,还拿上文那个例子来看,如果你只能进行单线程,那你就麻烦了,你只能控制你的手或者眼,不能同时工作,你甚至连听写单词都难以完成,这就体现了多线程的重要之处了,它之所以存在,之所以要用它,就是因为它很重要。
举个数据库的例子,比如说你现在要先写入一个数据,同时读出它,如果不使用线程,你就不能实现这个同步进行的操作,可见使用线程的重要性。

怎么实现线程?

方法一:继承Thread类

1.创建一个类继承Thread。
2.重写Thread中的run方法,这里注意,线程启动时运行的是run里面的代码,所以要把代码写在run方法里去。
3.创建子类对象,由于子类继承了Thread,所以就是在创建线程。
4.启动线程start()或者run(),这两个并无区别,第一个是相当于使用start方法来启动这个线程,其实就是取运行run中的代码,而run就是直接调用run方法的代码了。

/**
 * All rights Reserved, Designed By DZF
 * @Title:  $P1
 * @Description:    $x使用继承实现线程
 * @author: DZF
 * @version V1.0
 * @Copyright: $DZF. All rights reserved.
 */
//P1类继承了Thread类
class P1 extends Thread
{
      public static void main(String args[])
      {
           P1 t= new P1();  //创建线程
           t.start();       //使用start()启动线程
           t.run();         //直接调用run()              
           System.out.println("主程序结束");
      }
      public void run()               
     //  覆盖run()  这是产生线程对象后就自动执行
      {
           System.out.println("线程"+getName()+"在运行");
      }
}

注意,由于计算机运行速度的不同,可能出现顺序的print的顺序有所不同,这也是在下文会讲到的问题。同时这种方式的缺陷是线程任务和线程是绑定在一起的。

方法二:使用Runnable接口

1.创建实现了Runnable接口的子类
2.重写Runnable接口中的run方法
3.创建实现了Runnable接口的子类的对象
4.创建Thread类的对象,也就是在创建线程
5.把实现了Runnable接口的子类对象作为参数传递给Thread类的构造方法

/**
 * All rights Reserved, Designed By DZF
 * @Title:  $P2
 * @Description:    $x使用接口实现线程
 * @author: DZF
 * @version V1.0
 * @Copyright: $DZF. All rights reserved.
 */

class Runthread implements Runnable{

    public void run() {
        System.out.println("DZF最帅");    //在使用了Runnable接口的类中重写run方法
    }

}

//P2将创建线程
public class P2{ 
    public static void main(String[] args){
        Runthread r = new Runthread();  //创建一个对象
        Thread t = new Thread(r);       //创建一个线程,把对象r传入其中,启动时运行r中的run方法
        t.start();
        System.out.println("没错,DZF就是最帅");
    }
}


这个程序似乎并不能看出Runnable有啥好处,那我就再写一个代码来体现一波Runnable的优点吧。
假装我很自恋,想让DZF最帅输出四次,如果继承Thread需要写四个类,很划不来,不如用Runnable接口实现,只需把这个Runnable类的对象传进四个Thread就好了。

/**
 * All rights Reserved, Designed By DZF
 * @Title:  $P2
 * @Description:    $x使用接口实现线程
 * @author: DZF
 * @version V1.0
 * @Copyright: $DZF. All rights reserved.
 */

class Runthread implements Runnable{

    public void run() {
        System.out.println("DZF最帅");    //在使用了Runnable接口的类中重写run方法
    }

}

//P2将创建线程
public class P2{ 
    public static void main(String[] args){
        Runthread r = new Runthread();  //创建一个对象

        /* 我现在想运行四个线程输出DZF最帅
         * 创建四个线程,把对象r传入其中,启动时运行r中的run方法*/
        Thread t  = new Thread(r);  
        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);
        Thread t3 = new Thread(r);
        t.start();
        t1.start();
        t2.start();
        t3.start();
    }
}

这种方法,把线程任务进行了描述,也就是面向对象,从而实现了线程任务和线程对象的分离。线程执行什么任务不再重要,只要是实现了Runnable接口的子类对象都可以作为参数传递给Thread的构造方法,此方式很灵活,大大减少了代码量。还有一个好处是实现接口了,还不影响继承其他父类,不想extends Thread一样,重写父类的run方法那么简单粗暴。


为了更加深入的了解上述两种方法,下文将举一些例子


1.使用继承Thread构造器传线程名及线程的sleep

/**
 * All rights Reserved, Designed By DZF
 * @Title:  $P3
 * @Description:    $x1.使用继承Thread构造器传线程名及线程的sleep
 * @author: DZF
 * @version V1.0
 * @Copyright: $DZF. All rights reserved.
 */
class pThread extends Thread{
    pThread(String str){
        //super()特指父类构造器,将String对象传入父类构造器中
        super(str);
    }
    public void run(){
        //覆盖父类的run方法
        for( int i = 1; i <= 3; i++ ){
            System.out.println( getName() + "运行第" + i + "次" );
            try{//在使用sleep时,需要使用try catch异常
                sleep(2000);
            }catch(InterruptedException e){}
            System.out.println( getName() + "已结束" );
        }
    }
}
/*主类将test上述类*/
public class P3{
    public static void main(String []args){
        pThread t1 = new pThread( "线程1" );
        pThread t2 = new pThread( "线程2" );
        t1.start();
        t2.start();
    }
}

2.使用Runnable接口的功能

/**
 * All rights Reserved, Designed By DZF
 * @Title:  $P3
 * @Description:    $x使用Runnable接口得功能
 * @author: DZF
 * @version V1.0
 * @Copyright: $DZF. All rights reserved.
 */

class P4 implements Runnable{
    public void run(){
        //覆盖run(),这是产生线程对象后就自动执行
        //由于使用Runnable接口,所以该类若想获取当前线程名,需要使用Thread.currentThread().getName()
        System.out.println("线程"+Thread.currentThread().getName()+"在运行");
    }
    //主函数将实现上述的线程
    public static void main(String args[]){
        P4 my = new P4(); // 创建对象
        Thread t= new Thread(my);   //  为对象创建线程
        t.start();
        System.out.println("主程序结束");
    }
}

3.线程的同步

我的目的是通过线程锁实现输出一个字母,然后输出一个数字,以此类推,这个时候就需要用synchronized实现了

/**
 * All rights Reserved, Designed By DZF
 * @Title:  $P6
 * @Description:    $使用同步代码块进行线程同步
 * @author: DZF
 * @version V1.0
 * @Copyright: $DZF. All rights reserved.
 */

class Share {
    private int data;
    private boolean available = false;//初始标记为false

    /*使用synchronized标记的代码块实现同步方法*/

    /*该方法判断数据是否写入,已写入则唤醒,否则继续锁死*/
    public synchronized int get()     {
        /*使用该方法,会通过判断标记选择是被唤醒还是继续等待*/
           while (available == false) {
               //如果是false,则线程一直wait,相当于被锁死
                try {
                    wait();
                    }
                catch(Exception e1){}
           }

           //true的时候,进行唤醒操作,同时将标记还原false
           available = false;
           notifyAll();
           return data;
     }

    /*该方法用于写入数据,同时改变标记*/
     public synchronized void put( int value ) {
            while (available == true) {
                   try {
                       wait();
                       }
                   catch(Exception e2){}
            }
            data = value;
            available = true;
            notifyAll();
  }
}
class Dispn extends Thread{
    private Share s1;
    public Dispn(Share s)
    {
        s1 = s;
    }
    public void run(){
         for(int i = 1 ; i <= 26; i++) {
                System.out.print(i + " ");
                s1.put(i);
                try {
                    sleep( (int)(Math.random()*100));
                }catch(Exception e1){}
         }
  }
}
class Dispch extends Thread{
    private Share s2;
    public Dispch(Share s2) {
        this.s2 = s2;
    }
    public void run(){
        char a = 'A';
        for(int j = 0; j < 26; j++ ){
            s2.get();
            System.out.print((char)(a + j) + " ");
        }
    }
}
public class P6{
    public static void main(String[] args){
       Share s = new Share();
       Dispn p = new Dispn(s);
       Dispch c = new Dispch(s);
       c.start();
       p.start();
     }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值