前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java学习之多线程

Java学习之多线程

作者头像
cherishspring
发布2019-10-14 16:38:11
4030
发布2019-10-14 16:38:11
举报
文章被收录于专栏:Java学习笔记Java学习笔记

1.继承Thread 类方式创建多线程

创建Thread类的子类时,首先声明子类的构造方法,其次用定义的run()方法覆盖Thread类的run()方法,即将自己要执行的程序区块写入run()方法中。

代码语言:javascript
复制
class ex_Thread extends Thread{
     int pauseTime;
     String name;
     public ex_Thread(int hTime,String hStr){
         pauseTime=hTime;
         name=hStr;
     }
      public void run(){
         Calendar now;//Calendar是Java系统提供的日期时间类的类型标识符
         int year,month,data,hour,minute,secend;
         for (int i=1;i<10;i++){
             try {
                 now=Calendar.getInstance();//取系统时间
                 year=now.get(Calendar.YEAR);//取年
                 month=now.get(Calendar.MONTH)+1;//取月
                 data=now.get(Calendar.DATE);//取日期值
                 hour=now.get(Calendar.HOUR_OF_DAY);//取小时值
                 minute=now.get(Calendar.MINUTE);//取分
                 secend=now.get(Calendar.SECOND);//取秒

                 //显示时间
                 System.out.println(" "+name+"时间:"+year+"年"+month+"月"+data+"日"+hour+"小时"+minute+"分"+secend+"秒");
                 Thread.sleep(pauseTime);
             }catch (Exception e){
                 System.out.println("线程错误"+e);
             }
         }
     }
      public static void main(String args[]){
         //A线程执行一次后睡眠2000毫秒
         ex_Thread myThread1=new ex_Thread(2000,"线程A");
         myThread1.start();

         //B线程执行一次后睡眠1000毫秒
         ex_Thread myThread2=new ex_Thread(1000,"线程B");
         myThread2.start();
     }
}

2.Runnable接口方式创建多线程

Runnable接口只有一个方法run(),用户新建线程的操作就由这个方法决定。run()方法必须由实现此接口的类来实现。定义好run()方法后,当用户程序需要建立新线程时,只要以这个实现了run()方法的类为参数创建系统类Thread的对象,就可以把用户实现的run()方法继承过来。

代码语言:javascript
复制
//主程序
public class ex_Thread1 extends JApplet {
    public void init(){
        //得到窗口容器对象
        Container cp=getContentPane();
        CString pa=new CString();//创建JPanel对象
        CSquare pal=new CSquare();//创建JPanel类的对象
        pa.setPreferredSize(new Dimension(300,150));
        pa.setBackground(Color.cyan);//设置pa的对象背景颜色
        pal.setPreferredSize(new Dimension(300,150));
        pal.setBackground(Color.cyan);//设置pal的对象背景颜色
        //cp容器的布局为BorderLayout,添加pa及pal的对象到cp容器中
        cp.add(pa,BorderLayout.NORTH);
        cp.add(pal,BorderLayout.SOUTH);
    }
}

//实现屏幕矩形框走动的线程程序
public class CSquare extends JPanel implements Runnable {
    int x1,y1,w1,h1;
    Thread th2=new Thread(this);
    public CSquare(){
        x1=5;y1=100;w1=40;h1=40;
        start();
    }
    private void start(){
        th2.start();
    }
    public void run(){
        while(true){
            x1=x1+5;
            if (x1==250)
                x1=0;
            repaint();//repaint()方法调用paint()方法重画矩形框
            try {
                Thread.sleep(500);//使th2线程睡眠500ms
            }catch (InterruptedException e){}
        }//while
    }
    public void paint(Graphics g){
        super.paint(g);
        Graphics2D g2=(Graphics2D) g;
        Rectangle2D.Double rec1=new Rectangle2D.Double(x1,y1,w1,h1);
        g2.draw(rec1);
    }
}


//实现屏幕上的字符"Hello Java"走动的线程程序
public class CString extends JPanel implements Runnable {
    int x=10,y=50;
    String Message="Hello Java";//字符串对象
    Font f=new Font("TimesRoman",Font.BOLD,24);//创建字体对象
    Thread th1=new Thread(this);
    public CString(){
        start();
    }
    private void start(){
        th1.start();
    }
    public void run(){
        while (true){
            x=x-5;
            if (x==0)
                x=300;
            repaint();//调用paint()方法重画字符串
            try {
                Thread.sleep(500);//使线程睡眠500ms
            }catch (InterruptedException e){}
        }//while
    }//run
    public void paint(Graphics g){
        super.paint(g);
        Graphics2D g2=(Graphics2D) g;
        g2.setFont(f);//设置字体
        g2.drawString(Message,x,y);
    }
}

3.多线程的管理

3.1 线程调度
3.1.1 优先抢占式调度

当线程优先级不同时,为保证优先级最高的线程先运行而采用优先抢占式调度算法。即优先级最高的线程优先抢占CPU。

3.1.2 轮转调度

当若干个线程具有相同的优先级时,可采用队列轮转调度法,即当一个线程运行结束时,该优先队列中排在最前面的线程运行。

3.2 线程优先级

Java线程的优先级是在1~10之间的正整数,数值越大,优先级越高。未设定优先级的线程其优先级取缺省值5。Java线程的优先级设置遵从下列规则:

  • 线程创建时,子线程继承父线程的优先级。
  • 线程创建后,可在程序中通过调用setPriority()方法改变线程的优先级。
  • 标识符常量MIN_PRIORITY表示优先级为1,NORM_PRIORITY表示优先级为5,MAX_PRIORITY表示优先级为10。其他级别的优先级可以直接用1~10之间的整数来设置,也可以标识符常量的基础上加一个常数。例如setPriority(Thread.NORM_PRIORITY+3)优先级为8。
代码语言:javascript
复制
class ThreadPriority{
    public static void main(String[] args) {
        Thread first=new myThread("A线程");//创建A线程
        first.setPriority(Thread.MIN_PRIORITY);//设置A线程优先级为1
        Thread second=new myThread("B线程");//创建B线程
        second.setPriority(Thread.NORM_PRIORITY+1);//设置B线程优先级为6
        Thread third=new myThread("C线程");//创建C线程
        third.setPriority(Thread.MAX_PRIORITY);//设置C线程优先级为10

        first.start();
        second.start();
        third.start();
    }
}
 class myThread extends Thread {
    String message;
    myThread(String message){
        this.message=message;
    }
    public void run(){
        for (int i=0;i<2;i++)
            System.out.println(message+" "+getPriority());
    }
}

可以看出,虽然线程C在程序中最后调用start()方法进入就绪状态,但是由于优先级最高,因此是最先执行的。

3.3 线程同步

由于Java支持多线程,并具有并发的功能,大大提高了计算机的处理能力。在各线程之间不存在共享资源的情况下,几个线程的执行顺序是随机的。但是,当两个或两个以上线程需要共享同一资源时,线程之间的执行次序就需要协调,并且在某个线程占用这一资源时,其他线程只能等待。

如生产者和消费者问题。为了不发生混乱,规定:生产者往货架上放货物时不允许消费者在取走货物,当消费者取走货物时不允许生产者放货物。这种机制在操作系统中称为线程间的同步。在同步机制中,那些访问临界资源的程序段称为临界区

在Java系统中,临界区程序段用关键字"synchronized"来标注,并通过一个称为监控器的系统软件来管理的。当执行被冠以synchronized的程序段即临界区程序时,监控器将这段程序(访问的临界资源)加锁,此时,称线程占有临界资源,直到这段程序执行完,才释放锁。只有锁被释放后,其他程序才可以访问这些临界资源。

定义临界区的语句:synchronized (expression) statement

expression 代表类名,是可选项。statement可以是一个方法,也可以是一个语句或一个语句块,最常见的是一个方法。

代码语言:javascript
复制
public class ThreadTB {
    public static void main(String[] args) {
        HoldInt h=new HoldInt();//h为监控器
        ProduceInt p=new ProduceInt(h);
        ConsumeInt c=new ConsumeInt(h);
        p.start();
        c.start();
    }
}
class HoldInt{
    private int sharedInt;
    private boolean writeAble=true;//writeAbke=true表示生产者线程能生产新数据
    public synchronized void set(int val){//临界区程序段,也称为同步方法
        while (!writeAble){//生产者线程不能生产新数据时进入等待
            try{wait();}
            catch(InterruptedException e){}
        }//生产者被唤醒后继续执行下面的语句
        writeAble=false;
        sharedInt=val;
        notify();
    }
    public synchronized int get(){//同步方法
        while (writeAble){//消费者线程不能消费数据时进入等待状态
            try{wait();}
            catch (InterruptedException e){}
        }//消费者被唤醒后继续执行下面语句
        writeAble=true;
        notify();
        return sharedInt;
    }
}
//ProduceInt 是生产者线程
class ProduceInt extends Thread{
    private HoldInt hi;
    public ProduceInt(HoldInt hiForm){
        hi=hiForm;
    }
    public void run(){
        for (int i=1;i<=4;i++){
            hi.set(i);
            System.out.println("产生的新数据是:"+i);
        }
    }
}
//ConsumeInt是消费者线程
class ConsumeInt extends Thread{
    private HoldInt hi;
    public ConsumeInt(HoldInt hiForm){
        hi=hiForm;
    }
    public void run(){
        for (int i=1;i<=4;i++){
            int val=hi.get();
            System.out.println("读到的数据是:"+val);
        }
    }
}

运行结果如下:

产生的新数据是:1 读到的数据是:1 读到的数据是:2 产生的新数据是:2 读到的数据是:3 产生的新数据是:3 读到的数据是:4 产生的新数据是:4

3.3 线程组

Java系统的每个线程都属于某一个线程组。采用线程组结构以后,可以对多个线程进行集中管理。如:同时启动,挂起或终止一个线程组中的全部线程。 Java系统专门在java.lang包中提供了ThreadGroup类来实现对线程组的管理功能。 大多数情况下,一个线程属于哪个线程组是由编程人员在程序中指定的,若编程人员没有指定,则java系统会自动将这些线程归于“main”线程组。main线程组是java系统启动时创建的。 一个线程组不仅可以包含多个线程,而且线程组中还可以包含其他的线程组,构成树形结构。 一个线程可以访问本线程组的有关信息,但无法访问本线程组的父线程组。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019 年 09 月,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.继承Thread 类方式创建多线程
  • 2.Runnable接口方式创建多线程
  • 3.多线程的管理
    • 3.1 线程调度
      • 3.1.1 优先抢占式调度
      • 3.1.2 轮转调度
    • 3.2 线程优先级
      • 3.3 线程同步
        • 3.3 线程组
        相关产品与服务
        容器服务
        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档