进程>线程,一个进程中可以有i
在一个进程中如果有多个线程,那么线程(cpu执行和调度的单位)是交替进行的,这是被模拟出来的,因为只有一个cpu只能处理一个线程,快速切换使我们看着是同时进行的
真正的多线程是拥有多个cpu就可以实现真正的同时进行
有以下几点需要我们注意:
1.线程就是独立执行的路径
2.程序执行时即使没有创建线程,后台也有多个线程,如:主线程,gc线程
3.mian()称为主线程,是系统的入口,用于执行整个程序
4.对同一份资源进行操作时,会出现资源抢夺的问题,需要加入并发控制
5.线程会增加消耗,比如时间,cpu调度时间的消耗
6.每个线程在自己工作内存交互,内存控制不当会导致数据不一致
在需要创建线程的类继承Thread,继承后必须重写run()方法
public class demo extends Thread{
public void run(){
for (int i = 0; i < 20; i++) {
System.out.println("我在吃饭 "+i);
}
}
public static void main(String[] args) {
demo thread = new demo();
thread.start();
for (int i = 0; i < 20; i++) {
System.out.println("我正在看书 "+i);
}
}
}
交替速度与电脑cpu有关,调用start方法多线程执行
创建线程:类名 引用变量 = new 类名();
利用工具包commons-io编写程序下载网图
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class demo2 extends Thread{
private String url;
private String name;
public demo2(String url,String name){
this.url = url;
this.name = name;
}
public void run(){
WebDownLoader webDownloader = new WebDownLoader();
webDownloader.downloader(url,name);
System.out.println("下载了文件名为"+name);
}
public static void main(String[] args) {
demo2 thedemo1 = new demo2("https://i1.hdslb.com/bfs/archive/75b12ea49e8d7cc6cd2d0ada331f9851fe5ad27c.jpg@672w_378h_1c_!web-search-common-cover.webp","1.jpg");
demo2 thedemo2 = new demo2("https://i1.hdslb.com/bfs/archive/c9958e7a5a8553c1a93aa1787ef5847e06748650.jpg@672w_378h_1c_!web-search-common-cover.webp","2.jpg");
demo2 thedemo3 = new demo2("https://i1.hdslb.com/bfs/archive/41575b1afec5305fa329d1cdf853373955d4e62a.jpg@672w_378h_1c_!web-search-common-cover.webp","3.jpg");
thedemo1.start();
thedemo2.start();
thedemo3.start();
}
}
class WebDownLoader{
//下载方法
public void downloader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO异常,downloader方法出行问题");
}
}
}
相较于Thread类,两者相差不大,多了一个代理的方式
Thread类创建:Thread thread = new thread();
然后 thread.start();
Runnable接口:创建一个代理(类名 引用变量 = new 类名();)
然后 new Thread(引用变量,线程名).start();
推荐使用Runnable,Thread需要继承有单继承的局限性
多个线程同时操作一个资源时会导致数据紊乱,不安全
如以下模拟抢票代码
public class demo implements Runnable{
private int tick = 10;
@Override
public void run() {
while (true){
if (tick<=0){
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+"拿到了第"+(tick--)+"张票");
}
}
public static void main(String[] args) {
demo thedemo = new demo();
new Thread(thedemo,"小明").start();
new Thread(thedemo,"陈平安").start();
new Thread(thedemo,"黄老师").start();
}
}
有拿到相同票的,有拿到-1张票的,数据紊乱
public class demo implements Runnable{
private String winner;
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
if (Thread.currentThread().getName().equals("兔子")&&i%10==0){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
if (gameover(i)){
break;
}
System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
}
}
private boolean gameover(int steps){
if (winner!=null){
return true;
}
//编写判断是否比赛结束的方法
{
if(steps==100){
winner = Thread.currentThread().getName();
System.out.println("winner is "+winner);
return true;
}
}
return false;
}
public static void main(String[] args) {
demo thedemo = new demo();
new Thread(thedemo,"兔子").start();
new Thread(thedemo,"乌龟").start();
}
}
接口Callable
然后重写call方法
//创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(3);
//提交执行
Future r1 = ser.submit(thedemo1);
Future r2 = ser.submit(thedemo2);
Future r3 = ser.submit(thedemo3);
//获取结果
try {
boolean rs1 = r1.get();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
try {
boolean rs2 = r2.get();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
try {
boolean rs3 = r3.get();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
//关闭服务
ser.shutdown();
总共5个步骤
必须有一个真实对象,然后将对象放入代理类中,代理类帮助真实对象完成一些其无法完成的操作
而不干涉真实对象本身,真实对象可以做自己的事情
注意:真实对象和代理要实现同一个接口
public class demo {
public static void main(String[] args) {
new WeddingCompeny(new You()).happyMarry();
}
}
interface Marray{
void happyMarry();
}
class You implements Marray{
@Override
public void happyMarry() {
System.out.println("你要结婚了,新郎不是我");
}
}
class WeddingCompeny implements Marray{
private Marray target;
public WeddingCompeny(Marray target){
this.target = target;
}
@Override
public void happyMarry() {
before();
this.target.happyMarry();
after();
}
private void after(){
System.out.println("收款");
}
private void before(){
System.out.println("布置婚礼");
}
}
函数式接口的定义:
任何接口,如果只包含一个抽象方法,那么它就是一个函数接口
对于函数式接口可以使用Lamda表达式来创建该接口对象
本身是用于简化代码,可以由匿名内部类推导,去掉无用代码,留下核心逻辑,修饰词、返回值的类型、类名、类接口都去掉
public class demo2 {
public static void main(String[] args) {
Face face = ()->{
System.out.println("you know what i mean");
};
face.fackbook();
}
}
interface Face{
void fackbook();
}
Lamda表达式还有三种简化方式
public class demo2 {
public static void main(String[] args) {
//1.参数类型简化
Face face = (a)->{
System.out.println("you know what i mean"+a);
};
face.fackbook(1);
//2.简化括号
Face face1 = a->{
System.out.println("you know what i mean"+a);
};
face1.fackbook(2);
//3.去掉花括号(代码只有一行的情况下可以去掉)
Face face2 = a->System.out.println("you know what i mean"+a);
}
}
interface Face{
void fackbook(int a);
}