区别
线程是CPU调度的最小单位,进程是资源分配的最小单位。进程是线程的容器,真正完成代码执行的是线程,而进程则作为线程的执行环境。
实现多线程
·继承Thread类;
·实现Runnable接口(Callable接口,知道就行);
线程启动都是Thread的start启动
继承Thread类一个小实例
package cn.xst.textdemo;
class MyThread extends Thread{ //这就是一个多线程的操作类
private String name;
public MyThread(String name){
this.name=name;
}
@Override
public void run() { //覆写run方法,作为线程的主体操作方法
for(int x=0;x<200;x++){
System.out.println(name+":"+x);
}
}
}
public class XianChengThread {
public static void main(String[] args) {
MyThread mta=new MyThread("线程A");
MyThread mtb=new MyThread("线程B");
MyThread mtc=new MyThread("线程C");
mta.start(); //如果某一个线程重复启动就会抛出异常
mtb.start();
mtc.start();
}
}
Thread有单继承局限,所以最好就是用Runnable接口
在接口里面任何的方法都是public定义的权限,不存在默认的权限只需要让一个类实现Runnable接口就可以,并且需要覆写run()方法
实现Runnable接口
package cn.xst.textdemo;
class MyThread implements Runnable{
private String name;
public MyThread(String name){
this.name=name;
}
@Override
public void run() {
for(int x=0;x<200;x++){
System.out.println(name+":"+x);
}
}
}
public class XianChengThread {
public static void main(String[] args) {
MyThread mta=new MyThread("线程A");
MyThread mtb=new MyThread("线程B");
MyThread mtc=new MyThread("线程C");
new Thread(mta).start();
new Thread(mtb).start();
new Thread(mtc).start();
}
}
结构上是一致的,如果继承的是Thread类,那么可以直接继承start方法,但是如果实现的是Runnable接口,没有start方法
功能区别
- Thread类是Runnable接口的子类,使用Runnable接口实现多线程可以避免单继承局限
- Runnable接口实现的多线程可以与Thread类实现的多线程更加清楚的描述数据共享的概念 (几个相同的new Thread(mta).start(); 这样就是几个线程抢mta的资源)
线程的命名
要想进行线程名称的的操作,可以使用Thread类的方法 以下都是Thread的方法
- 构造方法:public Thread(Runnable target,String name);
- 设置名字:public final void setName(String name);
- 取得名字:public final String getName();
- 取得当前线程对象:public static Thread currentThread();
package cn.xst.textdemo;
class MyMingM implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());//表示取得当前对象的名字
}
}
public class XianChengMM {
public static void main(String[] args) {
MyMingM ma=new MyMingM();
MyMingM mb=new MyMingM();
MyMingM mc=new MyMingM();
new Thread(ma,"萧胜天").start();
new Thread(mb,"郭泽彬").start();
new Thread(mc).start();
ma.run();//返回main 主方法就是一个线程(main线程)
}
}
原来主方法就是一个线程(main线程),那么所有在主方法上创建的线程实际上都可以将其表示为子线程
每一个JVM进程启动的时候至少启动几个线程
- main线程:程序的主要执行,以及启动子线程
- gc线程:负责垃圾收集
线程休眠
所谓的线程休眠指的是让线程的执行速度稍微变慢一点,休眠的方法: 也是属于Thread
·public static void sleep(long millis)这是毫秒throws InterruptedException 1000毫秒==1秒
package cn.xst.textdemo;
class Xss implements Runnable{
@Override
public void run() {
for(int x=0;x<1000;x++){
try {
Thread.sleep(1000); //这个方法本身就是抛出了一个异常 1000毫秒==1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+", x="+x);
}
}
}
public class XianChengXM {
public static void main(String[] args) {
Xss x=new Xss();
new Thread(x,"萧胜天").start();
new Thread(x,"郭**").start();
new Thread(x,"陈**").start();
new Thread(x,"网管").start();
new Thread(x,"小黑").start(); //这里他们是在抢占资源
}
}
线程优先级
所谓的优先级指的是越高的优先级,越有可能先执行
- 设置优先级:public final void setPriority(int newPriority)
- 取得优先级:public final int getPriority()
发现设置和取得优先级都是使用了int数据类型,对于此内容有三种取值;
- 最高优先级:public static final int MAX_PRIORITY; 10
- 中等优先级:public static final int NORM_PRIORITY; 5
- 最低优先级:public static final int MIN_PRIORITY; 1
package cn.xst.textdemo;
class YXJ implements Runnable{
@Override
public void run() {
for(int x=0;x<1000;x++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+", x="+x);
}
}
}
public class XianChengYNJ {
public static void main(String[] args) {
YXJ yxj=new YXJ();
Thread y=new Thread(yxj,"线程A");
Thread x=new Thread(yxj,"线程B");
Thread j=new Thread(yxj,"线程C");
y.setPriority(Thread.MAX_PRIORITY);
x.setPriority(Thread.MIN_PRIORITY);
j.setPriority(Thread.NORM_PRIORITY);
y.start();
x.start();
j.start();
}
}
主线程属于中等优先级
同步与死锁
实际上所谓的同步指的是就是多个线程访问同一资源时所需要考虑到的问题
package cn.xst.textdemo;
class Tb implements Runnable{
private int ticket=5;
@Override
public void run() {
for(int x=0;x<20;x++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(this.ticket>0){
System.out.println(Thread.currentThread().getName()+", 卖票="+ticket--);
}
}
}
}
public class XianChengTB {
public static void main(String[] args) {
Tb t=new Tb();
new Thread(t,"线程A").start();
new Thread(t,"线程B").start();
new Thread(t,"线程C").start();
}
//这是三个线程在抢占卖票 每个人都在
}
同步问题在于
在抢占的时候 先判断是否有剩余票
再进行 休眠延迟
再修改剩余票数
因此解决同步问题在于把以上的三个步骤都合起来叫做同步
要想实现线程的同步可以使用 synchronized 关键字
- 一种是同步代码块
- 另一种是同步方法
同步代码块
package cn.xst.textdemoa;
class Tb implements Runnable{
private int ticket=500;
@Override
public void run() {
synchronized(this){ //当前操作每次只允许一个对象进入
for(int x=0;x<200;x++){
if(this.ticket>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖票="+this.ticket--);
}
}
}
}
}
public class XianChengTB {
public static void main(String[] args) {
Tb t=new Tb();
new Thread(t,"线程A").start();
new Thread(t,"线程B").start();
new Thread(t,"线程C").start();
new Thread(t,"线程D").start();
}
}
同步方法
package cn.xst.textdemoa;
class Tb implements Runnable{
private int ticket=500;
@Override
public void run() {
for(int x=0;x<200;x++){
this.sale(); //调用同步方法
}
}
public synchronized void sale(){ //把要锁住的单独放在一个同步方法里
if(this.ticket>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖票="+this.ticket--);
}
}
}
public class XianChengTB {
public static void main(String[] args) {
Tb t=new Tb();
new Thread(t,"线程A").start();
new Thread(t,"线程B").start();
new Thread(t,"线程C").start();
new Thread(t,"线程D").start();
}
}
请解释多个线程访问同一资源时需要考虑到哪些情况?有可能带来那些问题
多个线程访问同一资源时一定要处理好同步,可以使用同步代码块或同步方法来解决
|-同步代码块:synchronized(锁定对象){代码} |-同步方法:public synchronized 返回值 方法名称(){代码}
但是过多的使用同步,有可能造成死锁