java中的多线程

1.概念

(1)程序

 程序是为完成特定任务,用某种语言编写的一组指令的集合。即一组静态的代码。(编译好的二进制文件,放在磁盘上)

(2)进程

进程是计算机中正在运行的程序,如运行中的QQ,微信等。(进程是操作系统进行资源分配的最小单位)

(3)线程

进程可以细化为一个线程,线程是一个进程内部的最小执行单元,是操作系统进行任务调度的最小单元。(例如:当启动QQ时可以同时开启多个聊天窗口,这些聊天窗口就是线程)

(4)进程与线程的关系

1.一个进程可以有多个线程。

2.一个线程只属于一个进程。(例如:QQ里的聊天窗口只属于QQ进程,不属于微信进程)

3.一个进程至少有一个线程,称为主线程。(例如:例如:启动QQ时至少有一个聊天窗口)

4.在主线程中可以创建并启动其它的线程;

5.一个进程内的所有线程共享该进程的内存资源。

2.线程的创建

(1)单线程

一般程序都是按照调用顺序依次往下执行的,不会出现交替执行的情况,如果要出现程序交替的情况,就要实现多线程,多线程就是一个进程在执行过程中可以实现多个线程,多个线程运行时是相互独立的。

例如:

package XC;
public class DXC {
    public void run()
    {
        for (int i = 0; i <100 ; i++) {
            System.out.println("run");
        }
    }
}

package XC;
public class TestDXC {
    public static void main(String[] args) {
        DXC dxc=new DXC();
        dxc.run();
        for (int i = 0; i < 100; i++) {
            System.out.println("main"+i);
        }
    }
}

上述代码run方法里的程序执行完后才会执行main。单线程按顺序执行。

(2)创建方式1:继承Thread类

在Java中要实现线程,最简单的方式就是扩展Thread类,重写其中的run方法,方法原型如下:
Thread类中的run方法本身并不执行任何操作,如果我们重写了run方法,当线程启动时,它将执行
run方法。
举例:
package XC;
public class Thread1 extends Thread{
    @Override
    public void run() {//重写了Thread的run方法,run方法相当于继承了Thread子类要执行的任务
        for (int i = 0; i < 100; i++) {
            System.out.println("run:"+i);
        }
    }
}
package XC;
public class TestThread {
    public static void main(String[] args) {
        Thread1 thread1=new Thread1();//创建实例Thread1对象
        thread1.start();//启动线程
        for (int i = 0; i < 100; i++) {
            System.out.println("main:"+i);
        }
    }
}

    

如图多线程不是按照程序执行顺序执行的,顺序不固定,main线程和继承了Thread类的Thread1类执行顺序不一定,两个线程是相互独立的,执行顺序取决于CUP的性能,和计算机相应的硬件。

(2)创建方式2:实现Runnable接口

实现Runnable接口的方式:
  java.lang.Runnable接口中仅仅只有一个抽象方法:
public void run()。
  也可以通过实现Runnable接口的方式来实现线程,只需要实现其中的run方法。
  Runnable接口的存在主要是为了解决Java中不允许多继承的问题。
package ThreatTicket;
public class RunnaberTicket implements Runnable{
    int num=10;
    @Override
    public void run() {
        while (true) {
            synchronized (this) {//给当前线程加锁,让窗口一和窗口二各自独立买票
                if (num > 0) {
                    try {
                        Thread.sleep(500);//让当前正在运行的线程停止500微秒
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "买到的是第" + num + "张票");
                    num--;
                } else
                    break;

            }
        }
    }
}
package ThreatTicket;

import sun.swing.AccumulativeRunnable;

public class TestRunnable {
    public static void main(String[] args) {
//线程执行的任务执行了两次,只创建了一个任务对象,与继承了Thread的类不同
     RunnaberTicket runnable=new RunnaberTicket();
     Thread thread=new Thread(runnable);
         thread.setName("窗口一");
        thread.start();
        Thread thread1=new Thread(runnable);
        thread1.setName("窗口二");
        thread1.start();

    }
}

使用实现Runnable接口方式创建线程,适用于在多个线程共享一个资源时使用,这样就不用使用静态变量,继承Thread方式创建的线程,在创建继承Thread类的对象时,多个线程会创建多个对象,这时多个对象共享一个资源时就会出现问题,导致可能多个线程买到同一个票,或者买到0个票,例如多个窗口买票问题,每个窗口是一个线程。
例如:
package ThreatTicket;

import com.sun.deploy.security.SelectableSecurityManager;

public class Ticket extends Thread{
   static int num=10;//static修饰的变量静态变量,只有一份
   static Object object=new Object();//synchronized同步锁的对象,同步锁的对象必须是唯一的
    @Override
    public void run() {
       while (true)
       {  synchronized (object)
       {  if(num>0)
           {
               try {
                   Thread.sleep(500);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               System.out.println(Thread.currentThread().getName()+"买到的是第"+num+"张票");
                num--;
           }
           else
               break;

       }}
    }
}
package ThreatTicket;
public class TestTicket {
    public static void main(String[] args) {
        Ticket ticket=new Ticket();
        ticket.setName("窗口1");
        ticket.start();
        Ticket ticket1=new Ticket();
        ticket1.setName("窗口2");
        ticket1.start();
    }
}

3.线程同步

(1)线程同步就是排队加锁多个线程同时读写同一份共享资源时,可能会引起冲突。所以引入线程“同步”机制, 即各线程间要有先来后到;

几个线程之间要排队,一个个对共享资源进行操作,而不是同时进行操作, 为了保证数据在方法中被访问时的正确性,在访问时加入锁机制。

举例:下述代码是实现Runnable接口的买票,与上述第二个创建线程二的实现Runnable接口的买票一样,只不过在run方法中线程共享的买票没加synchronized,即为没加锁,这两个线程就会同时进到买票中,会导致两个线程买到同一张票,或者买到零张票,

package ThreatTicket;
public class RunnaberTicket implements Runnable{
    int num=10;
    @Override
    public void run() {
        while (true) {

                if (num > 0) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "买到的是第" + num + "张票");
                    num--;
                } else
                    break;


        }
    }
}
package ThreatTicket;

import sun.swing.AccumulativeRunnable;

public class TestRunnable {
    public static void main(String[] args) {
     RunnaberTicket runnable=new RunnaberTicket();
     Thread thread=new Thread(runnable);
         thread.setName("窗口一");
        thread.start();
        Thread thread1=new Thread(runnable);
        thread1.setName("窗口二");
        thread1.start();

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值