多线程

线程是什么?

一个线程是线程一个顺序执行流。

同类的多个线程共享一块内存空间和一组系统资源,线程本身有一个供程序执行时的栈堆。线程在切换时负荷小,因此,线程也被称为轻负荷进程。一个进程中可以包含多个线程。

线程什么时候使用?

线程通常用于在一个程序中需要同时完成多个任务的情况。我们可以将每个任务定义一个线程,使他们得以一同工作。

也可以用于在单一线程中可以完成,但是使用多线程可以更快的情况。

线程创建

继承Thread类

public class Thread implements Runnable

Thread 类实现了 Runnable 接口,它们之间具有多态关系。

其实,使用继承 Thread 类的方式实现多线程,最大的局限就是不支持多继承

public class XC extedns Thread{

}

实现 Runnable 接口

语法:

public class thread extends Object implements Runnale{

}

从 JDK 的 API 中可以发现,实质上 Thread 类实现了 Runnable 接口,其中的 run() 方法正是对 Runnable 接口中 run() 方法的具体实现。

继承 Thread 类的优缺点

当一个 run() 方法体现在继承 Thread 类中时,可以用 this 指向实际控制运行的 Thread 实例。因此,代码不需要使用以下控制语句:

Thread.currenThread().sleep();

不再使用上面的控制语句,而是可以简单地使用 Threadsleep() 方法,继承 Thread 类的方式使代码变得简单易读。

实现 Runnable 接口的优缺点

从面向对象的角度来看,Thread 类是一个虚拟处理机严格的封装,因此只有当处理机模型修改或扩展时,才应该继承该类。由于 Java 技术只允许单一继承,因此如果已经继承了 Thread 类,就不能再继承其他任何类,这会使用户只能采用实现 Runnable 接口的方式创建线程。

实例:

/**
* 线程创建
* 2种方式:
* 继承 Thread类
* 实现接口 Runnable
* @author soft01
*
*/
//class Xc extends Thread{//创建线程所需要继承的的类
// public void run() {//run方法是覆盖父类方法
// for(int i=0;i<20;i++) {
// System.out.println("111");
// }
// }
//}
class Xc2 implements Runnable{//不是继承类,而改成了实现接口
public void run() {//run方法是覆盖父类方法
for(int i=0;i<20;i++) {
System.out.println("111");
}
}
}
public class One {
public static void main(String[] args) {
// Xc xc=new Xc();
// xc.run();
// xc.start();
/**
* 谁调用start方法,程序就去自动调用run方法
* start 会单开启一个线程,而不是直接调用。
*/
Xc2 xc2=new Xc2();
Thread a=new Thread(xc2);
a.start();
for(int i=0;i<20;i++) {
System.out.println("222");
}
} }

对线程生命周期中的 7 种状态做说明。

  1. 出生状态:用户在创建线程时所处的状态,在用户使用该线程实例调用 start() 方法之前,线程都处于出生状态。
  2. 就绪状态:也称可执行状态,当用户调用 start() 方法之后,线程处于就绪状态。
  3. 运行状态:当线程得到系统资源后进入运行状态。
  4. 等待状态:当处于运行状态下的线程调用 Thread 类的 wait() 方法时,该线程就会进入等待状态。进入等待状态的线程必须调用 Thread 类的 notify() 方法才能被唤醒。notifyAll() 方法是将所有处于等待状态下的线程唤醒。
  5. 休眠状态:当线程调用 Thread 类中的 sleep() 方法时,则会进入休眠状态。
  6. 阻塞状态:如果一个线程在运行状态下发出输入/输出请求,该线程将进入阻塞状态,在其等待输入/输出结束时,线程进入就绪状态。对阻塞的线程来说,即使系统资源关闭,线程依然不能回到运行状态。
  7. 死亡状态:当线程的 run() 方法执行完毕,线程进入死亡状态。

提示:一旦线程进入可执行状态,它会在就绪状态与运行状态下辗转,同时也可能进入等待状态、休眠状态、阻塞状态或死亡状态。

线程优先级

 线程的切换是由线程调度控制的,我们可以通过代码来干涉,但是我们可以通过提高线程的优先级来最大程度的改善线程获取时间片的几率。

线程的优先级被划分为10级,值分别为1-10,其中1最低,10最高。线程提供了3个常量来表示最低,最高,以及默认优先级:

        Thread.MIN_PRIORITY,

        Thread.MAX_PRIORITY,

        Thread.NORM_PRIORITY

线程同步

synchronized关键字

多个线程并发读写同一个临界时会发生“线程并发安全问题”

比如:

多线程共享实例变量

多线程共享静态公共变量

若要解决线程安全问题,需要将异步的操作变为同步操作。

异步操作:多线程并发的操作,相当于各干各的。

同步操作:有先后顺序的操作,相当于你完成后我在干。

synchronized关键字是java中的同步锁

线程休眠

sleep()方法的作用是在指定的毫秒数内让当前正在执行的线程“休眠”(暂停)

实例:

//线程睡眠
public class Four {
public static void main(String[] args) {
Xc5 xc5=new Xc5();
Thread c=new Thread(xc5);
c.start();
}
}
class Xc5 implements Runnable{
public void run() {//throws Exception
for(int i=0;i<2;i++) {
System.out.println(Thread.currentThread().getName()+""+i);
try {
Thread.sleep(1000);//毫秒
System.out.println("结束时间"+System.currentTimeMillis());
}catch(Exception e) { }
}
}
} //class Yy implements Runnable{
// public void run() throws Exception{
//
// }
//}
//class Xx extends Thread{
// public void run() throws Exception{
//
// }
//}
/**
* 用throws抛异常的时候,如果向主调处抛异常的方法是从父类继承的
* 或者从接口实现的。那么,覆盖父类方法或实现接口时,如果父类中的原方法
* 或接口中的原抽象方法没有抛异常,则子类覆盖父类的方法或实现接口的方法也不能抛异常
* 而出现这种情况只能用try...catch,大不了catch中什么都不写 */

线程让步

yiled()方法的作用是放弃当前CPU资源,将它让给其他的任务去占用CPU执行时间。

实例:

//线程让步
public class Five {
public static void main(String[] args) {
Xc6 xc6=new Xc6();
Thread a=new Thread(xc6);
Thread b=new Thread(xc6);
a.setName("线程一");
b.setName("线程二");
a.start();
b.start();
}
}
class Xc6 implements Runnable{
public void run() {
for(int i=0;i<=30;i++) {
System.out.println(Thread.currentThread().getName()+""+i);
if(i%1==0) {
Thread.yield();
}
}
}
}

锁机制

Java提供了一种内置的锁机制来支持原子性:

同步代码块(synchronized关键字),同步代码块包含两部分:一个作为锁的对象的引用,一个作为由这个锁保护的代码块。

        synchronized (同步监视器——锁对象引用){

            //代码块

        }

 若方法所有代码都需要同步也可以给方法直接加锁。

每个Java对象都可以用做一个实现同步的锁,线程进入同步代码块之前会自动获得锁,并且在退出同步代码块时自动释放锁,而且无论是通过正常途径退出还是通过抛异常退出都一样,获得内置锁的唯一途径就是进入由这个锁保护的同步代码块或方法。

选择合适的锁对象

使用synchroinzed需要对一个对象上锁以保证线程同步。那么这个锁对象应当注意:

多个需要同步的线程在访问该同步块时,看到的应该是同一个锁对象引用。否则达不到同步效果。

通常我们会使用this来作为锁对象。

选择合适的锁范围

 在使用同步块时,应当尽量在允许的情况下减少同步范围,以提高并发的执行效率。

静态方法锁

方法加锁:

public synchronized void xxx(){

}

那么该方法锁的对象是类对象。每个类都有唯一的一个类对象。获取类对象的方式:类名.class。

静态方法与非静态方法同时声明了synchronized,他们之间是非互斥关系的。原因在于,静态方法锁的是类对象而非静态方法锁的是当前方法所属对象。

synchronized 不仅可以用到同步方法,也可以用到同步块。对于同步块,synchronized 获取的是参数中的对象锁。

synchronized(obj)
{
//代码
}

实例:

class CP implements Runnable{
public static int chepiao=100;
public static String aa=new String("1");//字符串随意定义,定义在函数上边
//synchronized 作用是让它所管辖的代码部分,全部执行完否则全部不执行
public void run()
{//synchronized修饰函数不需要字符串,相当于默认是this
while(true)
{
synchronized (aa)
{//即可修饰代码块,又可以修饰函数
if(chepiao>0)
{
System.out.println("第"+Thread.currentThread().getName()+"个车站正在卖第"+(101-chepiao)+"张");
--chepiao;
}
else
{
break;
}
}
}
}
}
public class CP01 {
public static void main(String[] args) {
CP cp01=new CP();
Thread cc=new Thread(cp01);
CP cp02=new CP();
Thread dd=new Thread(cp02);
cc.start();
dd.start();
}
}

Day04:异常处理(二) / 多线程基础的更多相关文章

  1. C#编程总结(二)多线程基础

    C#编程总结(二)多线程基础 无论您是为具有单个处理器的计算机还是为具有多个处理器的计算机进行开发,您都希望应用程序为用户提供最好的响应性能,即使应用程序当前正在完成其他工作.要使应用程序能够快速响应 ...

  2. Java 多线程基础(十二)生产者与消费者

    Java 多线程基础(十二)生产者与消费者 一.生产者与消费者模型 生产者与消费者问题是个非常典型的多线程问题,涉及到的对象包括“生产者”.“消费者”.“仓库”和“产品”.他们之间的关系如下: ①.生 ...

  3. Java多线程基础知识例子

    一.管理 1.创建线程 Thread public class Main { public static void main(String[] args) { MyThread myThread = ...

  4. Java多线程基础知识笔记(持续更新)

    多线程基础知识笔记 一.线程 1.基本概念 程序(program):是为完成特定任务.用某种语言编写的一组指令的集合.即指一段静态的代码,静态对象. 进程(process):是程序的一次执行过程,或是 ...

  5. Java基础知识笔记(四:多线程基础及生命周期)

    一.多线程基础 编写线程程序主要是构造线程类.构造线程类的方式主要有两种,一种是通过构造类java.lang.Thread的子类,另一种是通过构造方法实现接口java.lang.Runnable的类. ...

  6. Java多线程干货系列—(一)Java多线程基础

    前言 多线程并发编程是Java编程中重要的一块内容,也是面试重点覆盖区域,所以学好多线程并发编程对我们来说极其重要,下面跟我一起开启本次的学习之旅吧. 正文 线程与进程 1 线程:进程中负责程序执行的 ...

  7. JAVASE02-Unit09: 多线程基础

    Unit09: 多线程基础 * 线程 * 线程用于并发执行多个任务.感官上像是"同时"执行 *  * 创建线程有两种方式. * 方式一: * 继承线程并重写run方法来定义线程要执 ...

  8. Java多线程干货系列(1):Java多线程基础

    原文出处: 嘟嘟MD 前言 多线程并发编程是Java编程中重要的一块内容,也是面试重点覆盖区域,所以学好多线程并发编程对我们来说极其重要,下面跟我一起开启本次的学习之旅吧. 正文 线程与进程 1 线程 ...

  9. 多线程基础(五)NSThread线程通信

    5.多线程基础 线程间通信   什么叫线程间通信 在一个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信   线程间通信的体现 1个线程传递数据给另一个线程 在1个线程中执行完特定任务后, ...

随机推荐

  1. Vue入门(三)——模拟网络请求加载本地数据

    1.首先我们需要在webpack.dev.conf.js中const PORT = process.env.PORT && Number(process.env.PORT) 的后面追加 ...

  2. Spring入门篇——第7章 Spring对AspectJ的支持

    第7章 Spring对AspectJ的支持 介绍Spring对AspectJ的支持 7-1 AspectJ介绍及Pointcut注解应用 实例 完成了在xml文件的配置 7-2 Advice定义及实例 ...

  3. free命令详解-1

    free命令可以显示Linux系统中空闲的.已用的物理内存及swap内存以及被内核使用的buffer.我们本篇学习如何使用free命令监控系统的内存情况. 一般使用free –m方式查看内存占用情况( ...

  4. BZOJ3032 七夕祭[中位数]

    发现是一个类似于“纸牌均分”的问题.然后发现,只要列数整除目标.行数整除目标就一定可以. 如果只移动列,并不会影响行,也就是同一行不会多不会少.只移动行同理. 所以可以把两个问题分开来看,处理起来互不 ...

  5. Orchard Core 使用工作流处理页面提交

    上一篇文章中:Orchard Core 使用工作流处理审批和创建内容项 我们介绍了如何使用工作流处理审批,通过此文章我们了解到工作流的简单使用.但提交数据来自于Postman 本次文章我将演示如何从页 ...

  6. opengles reference card

    https://www.khronos.org/files/opengles31-quick-reference-card.pdf https://www.khronos.org/opengles/s ...

  7. 两种atm取款方式

    1.//函数 密码 账号function User(username, password, account){ this.username = username; this.password = pa ...

  8. Oracle中dual表的用途

    dual是一个虚拟表,用来构成select的语法规则,oracle保证dual里面永远只有一条记录.我们可以用它来做很多事情,如下: 1.查看当前用户,可以在 SQL Plus中执行下面语句 sele ...

  9. windows下C语言头文件的运用

    头文件 singnext.dingswords printf("终止我每丝呼吸,让心灵穿透所有的秘密\n"); 头文件 singtocj.h printf("当无数的日月 ...

  10. C# ado.net DataSet使用(五)

    一.填充dataset class Program { private static string constr = "server=.;database=northwnd;integrat ...