自学内容网 自学内容网

第四章 多线程

1.进程与线程

一个程序只有一个进程

一个进程包含多个线程(必须有一个主线程)

查看线程

public static void main(String args[]) {
    Thread t = Thread.currentThread();  //获得当前线程
    System.out.println("当前线程是: "+t.getName()); 
    t.setName("MyJavaThread"); //更改线程的名字
    System.out.println("当前线程名是: "+t.getName()); 
}
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

2.线程的创建方式

(1)继承Thread类

继承Thread类,写run()方法,调用start()方法启动线程

public class MyThread extends Thread{
    //重写run()方法
    public void run(){
        for(int i=1;i<100;i++){         
            System.out.println(Thread.currentThread().getName()+":"+i);
    }
  }
}
​
public static void main(String[] args) {
    MyThread t1 = new MyThread();//创建第一个线程
    t1.start(); //启动线程
    
    MyThread t2 = new MyThread();//创建第二个线程
    t2.start(); //启动线程
}

(2)实现Runnable接口

实现Runnable接口,实现run()方法,调用start()方法启动线程

public class MyRunnable implements Runnable{
    public void run(){
        for(int i=1;i<100;i++){ 
            System.out.println(Thread.currentThread().getName()+":"+i);
    }
  }
}
​​​​​​​
public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread t = new Thread(myRunnable);  
        t.start(); //启动线程
}

(3)实现Callable接口

实现Callable<数据类型>,重写call方法 注意:Callable有返回值

/*
*子线程
*/
public class MyCallable implements Callable<String> {
​
   //重写call方法
   @Override
   public String call() throws Exception {
      //子线程执行的任务
      for (int i=0;i<20;i++){
        System.out.println(java.lang.Thread.currentThread().getName()+"===="+i);
       }
        return "这是MyCallable";
   }
}

​
public static void main(String[] args) {
​
    //FutureTask-->RunnableFuture -->Runnable
    MyCallable myCallable = new MyCallable();
​
    // FutureTask是一个实现了Runnable接口的类
    FutureTask<String> ft = new FutureTask<String>(myCallable);
​
    java.lang.Thread t1 = new java.lang.Thread(ft);
    t1.start();//启动线程
​
    try {
        //获得返回值
        System.out.println(ft.get());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

3.线程状态

创建状态:new Thread时

就绪状态:调用start()方法

运行状态:执行run()方法

阻塞状态:调用sleep,join 会进入阻碍状态,恢复后改为就绪状态-->运行状态

死亡状态:run()运行结束

4.线程常用方法

说 明
void setPriority(int newPriority)更改线程的优先级
static void sleep(long millis)在指定的毫秒数内让当前正在执行的线程休眠
void join()等待该线程终止
static void yield()暂停当前正在执行的线程对象,并执行其他线程
void interrupt()中断线程
boolean isAlive()测试线程是否处于活动状态
wait()暂停一个线程
notify唤起一个线程

注意:join写在哪个线程阻塞谁,谁就调用谁强制执行

sleep使用毫秒 1000ms =1s

//优先级
Priority p = new Priority();
​
Thread t1 = new Thread(p,"A");
t1.setPriority(10);
t1.start();
Thread t2 = new Thread(p,"B");
t2.setPriority(1);
t2.start();
​
//睡眠2秒
Thread.sleep(2000);
​
//查看线程活动
System.out.println(t.isAlive());

5.线程安全

多个线程一起操作同意共享资源时,将引发数据不安全问题

同步方法(synchronized)

使用synchronized修饰的方法控制对类成员变量的访问

synchronized就是为当前的线程声明一把锁

1.修饰方法体

public synchronized void sale() {   
    if (count <= 0) {
        flag = true;
        return;
   }
}

2.修饰代码块

public void run() {
        synchronized (this) {   
            //放同步代码块
  }
}
线程安全的类型

查看ArrayList类的add()方法定义

public boolean add(E e) {
      ensureCapacityInternal(size + 1); //集合扩容,确保能新增数据
      elementData[size++] = e;//在新增位置存放数据
      return true;
}

ArrayList类的add()方法为非同步方法

当多个线程向同一个ArrayList对象添加数据时,可能出现数据不一致问题

常见类型对比

1.Hashtable && HashMap

HashtableHashMap
继承关系 :实现了Map接口,Hashtable继承Dictionary类继承关系:实现了Map接口,继承AbstractMap类
线程安全,效率较低非线程安全,效率较高
键和值都不允许为null键和值都允许为null

2.StringBuffer && StringBuilder

StringBufferStringBuilder
线程安全非线程安全

原文地址:https://blog.csdn.net/2301_77897834/article/details/142610384

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!