java线程知识整理(上)

1 并发与并行
并发:指两个或多个事件在同一个时间段内发生。(交替发生)
并行:指两个或多个事件在同一时刻发生(同时发生)
  在操作系统中,安装了多个程序,并发指的是在一段时间内宏观上有多个程序同时运行,这在单 CPU 系统中,每一时刻只能有一道程序执行,即微观上这些程序是分时的交替运行,只不过是给人的感觉是同时运行,那是因为分时交替运行的时间是非常短的。
  而在多个 CPU 系统中,则这些可以并发执行的程序便可以分配到多个处理器上(CPU),实现多任务并行执行,即利用每个处理器来处理一个可以并发执行的程序,这样多个程序便可以同时执行。目前电脑市场上说的多核CPU,便是多核处理器,核 越多,并行处理的程序越多,能大大的提高电脑运行的效率。

2.进程与线程
进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。
线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程。

3.线程调度:
分时调度
所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。
抢占式调度
优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。
4.单线程与多线程
01.单线程
JVM执行main方法.main方法会进入到栈内存JVM会找操作系统开辟一条main方法通向cpu的执行路径cpu就可以通过这个路径来执行main方法而这个路径有一个名字,叫main(主)线程。
02.多线程
java传统创建多线程的两种方法
(1)通过创建Thread类的子类来实现。
(2)通过实现Runnable接口来实现。

注意:start方法开辟了新的栈空间,执行run方法,启动线程。

5.Thread 类
构造方法:
public Thread() :分配一个新的线程对象。
public Thread(String name) :分配一个指定名字的新的线程对象。
public Thread(Runnable target) :分配一个带有指定目标新的线程对象。
public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。
常用方法:
public String getName() :获取当前线程名称。
public void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。
public void run() :此线程要执行的任务在此处定义代码。
public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
public static Thread currentThread() :返回对当前正在执行的线程对象的引用。

6.Thread 和Runnable的区别
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
:线程方法1出现问题,抛出异常,接下来方法2就不会执行。
总结:
实现Runnable接口比继承Thread类所具有的优势:

  1. 适合多个相同的程序代码的线程去共享同一个资源。
  2. 可以避免java中的单继承的局限性。
  3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
  4. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。
    扩充:在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用
    java命令执行一个类的时候,实际上都会启动一个JVM,每一个JVM其实在就是在操作系统中启动了一个进
    程。

7.匿名内部类方式实现线程的创建
使用线程的内匿名内部类方式,可以方便的实现每个线程执行不同的线程任务操作。
匿名:没有名字
内部类:写在其他类内部的类
匿名内部类作用:简化代码
  把子类继承父类,重写父类的方法,创建子类对象合一步完成
  把实现类实现类接口,重写接口中的方法,创建实现类对象合成一步完成
匿名内部类的最终产物:子类/实现类对象,而这个类没有名字
格式:

new父类/接口(){
 重复父类/接口中的方法
};

练习

class MyThreaddomo extends Thread {
   @Override
public void run() {
    for (int i = 0; i < 20; i++) {
        System.out.println("线程名:" + Thread.currentThread().getName() + "、线程优先级:" + Thread.currentThread().getPriority() + "、第" + i);
    }
   }
}
 class MyRunnabledemo implements Runnable{
  	  @Override
  	  public void run() {
    for (int i = 0; i < 20; i++) {
        System.out.println("线程名:" + Thread.currentThread().getName() + "、线程优先	级:" + Thread.currentThread().getPriority() + "、第" + i);
    }
}
}
public class Mythreadtest01 {
public static void main(String[] args) {
  demo3();
  // demo2();
  //demo1();
}
private static void demo3() {
//匿名内部类方式实现线程的创建
    //方式一
    Runnable r = new Runnable(){
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
            System.out.println("new Runnable "+Thread.currentThread().getName());
            }
        }
    };
    new Thread(r).start();
    //方式二
    new Thread(){
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
            System.out.println("new Thread "+Thread.currentThread().getName());
            }
        }
    }.start();
}
private static void demo2() {
    //创建线程的方式1,继承Thread类
    MyThreaddomo mt = new MyThreaddomo();
    mt.setName("我是A线程");
    mt.setPriority(10);
    mt.start();
    //创建线程的方式2,实现Runnale接口
    MyRunnabledemo mr = new MyRunnabledemo();
    Thread t1 = new Thread(mr);
    t1.start();
    //多线程
    new MyThreaddomo().start();
    new MyThreaddomo().start();
}
private static void demo1() {
    //单线程
    //线程的一些方法
       for (int i = 0; i < 20; i++) {
     System.out.print("当前线程:"+Thread.currentThread().toString());//[线程名,优先级,线程组]
        System.out.print(" 线程名:"+Thread.currentThread().getName());
        System.out.print(" 优先级:"+Thread.currentThread().getPriority());
        //System.out.println(Thread.currentThread().getName()+","+i);
        System.out.println("线程名:"+Thread.currentThread().getName()+"、线程优先级:"+Thread.currentThread().getPriority()+"、第"+i);
    }
}
}

线程安全
如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

如何解决线程安全问题?
当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题。
要解决上述多线程并发访问一个资源的安全性问题:也就是解决重复票与不存在票问题,Java中提供了同步机制(synchronized)来解决。
三种方式完成同步操作
1 . 同步代码块。
2. 同步方法。
3. 锁机制。

01.同步代码块 : synchronized 关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。
格式:

创建一个锁对象Object obj = new Object();
synchronized(同步锁){
 需要同步操作的代码
}

同步锁:
对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁.

  1. 锁对象 可以是任意类型。
  2. 多个线程对象 要使用同一把锁。

注意:在任何时候,最多允许一个线程拥有同步锁,谁拿到锁就进入代码块,其他的线程只能在外等着(BLOCKED)。

02.同步方法 :使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外
等着。
格式:

public synchronized void method(){
 可能会产生线程安全问题的代码 
}

同步锁是谁?
对于非static方法,同步锁就是this。
对于static方法,我们使用当前方法所在类的字节码对象(类名.class)。
03.Lock 锁
java.util.concurrent.locks.Lock 机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作,
同步代码块/同步方法具有的功能Lock都有,除此之外更强大,更体现面向对象。
Lock锁也称同步锁,加锁与释放锁方法化了,如下:
public void lock() :加同步锁。
public void unlock() :释放同步锁。
Lock锁(JDK1.5之后)
第三种方式:Lock与unlock获取锁与释放锁。unlock放在finally代码块中。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值