分类 Default 下的文章

线程之前笔记

  1. 线程是操作系统能够进行运算调度的最小单位,是进程中的实际运作单位
  2. 线程和进程的区别

    1.每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销
    2.线程可以当成轻量级的进程,每个线程有独立的工作内存,切换开销小
    3.多进程:在操作系统中同时运行多个程序
    4.多线程:在同一程序中有多个顺序流(功能)同时执行(多核cpu)
    5.单线程:同一时间点只能有一个进程在执行(采用时间片轮转,让多个线程轮流执行。因为cpu执行速度快--假多线程)
  3. 线程理解

    每个分支都叫一个线程,main叫主分支(主线程)
    机器上的一个.class文件,机器上的一个.exe文件,这个叫做一个进程。程序的执行过程都是这样的:首先把程序的代码放到内存的代码区里面
    代码放到代码区后并没有马上开始执行,但这时候说明了一个进程准备开始,进程已经产生了,但还没有开始执行,这就是进程,所以进程其实是一个静态的概念,它本身就不能动
    平常所说的进程的执行指的是进程里面主线程开始执行了,也就是main()方法开始执行了。进程是一个静态的概念,在我们机器里面实际上运行的都是线程

    程序的执行流程:
    1.操作系统将分块的程序运输到内存对应的区间,过程中建立一个对应的表方便寻址
    2.当程序跑起来后根据局部性规律(当调用一块代码后,周围的代码也会被调用),一点点的调入内存中
    3.寻址过程中使用虚拟地址分配,就可以运行那些占较大内存的程序
  4. java中的线程

    java.lang.Thread 类的实例就是一个线程但是它需要调用java.lang.Runnable接口来执行,
    由于线程类本身就是调用的Runnable接口
    所以你可以继承java.lang.Thread 类或者直接调用Runnable接口(推荐)来重写run()方法实现线程
  5. 线程的创建和启动
  6. 继承Thread并重写run方法

    class MyThread extends Thread {
     public void run(){
    //线程体
     }
    }
  7. 实现Runnable接口

    //定义一个线程类
    public class ThreadTest implements Runnable{
     public void run() {
         // TODO Auto-generated method stub
                 线程体
     }
    }
    public class TestThread1{
     public static void main(String args[]){
         ThreadTest tt = new ThreadTest();
         tt.run();//就会执行run()方法再执行main方法
         Thread t = new Thread(tt);//启动一个新的线程需要Thread对象
         t.start();//启动新线程与主线程一起执行(交替执行)
         for(int i=0;i<10;i++){
             System.out.println("maintheod:"+i);
         }
     }
    }
    public static Thread currentThread()//获取当前线程的引用
  8. start与run

    start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,
    当调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程
  9. 线程状态转移

    阻塞状态(等待状态)
  • 创建一个新线程start准备好后进入就绪态(标上优先级别),进入cpu执行(线程调度器决定哪个线程进入运行态)
  • 时间片用完线程执行完后线程终止/遇到死锁后kill掉/时间片用完没有执行完的线程进入等待态
  1. 线程使用

    sleep(毫秒):休眠当前线程,进入等待状态,当休眠时间到解除等待状态,进入就绪状态等待cpu运行(睡眠时不会释放锁)
    yield()让出cpu给其他线程
    join()合并当前线程,让线程按照当前代码写的顺序执行
    wait():与synchronized关键字一起使用,进程进入等待状态,当notify/notifyall调用后解除等待态,wait调用后会释放锁,所以拿到锁后才可以运行
    setPriority()设置线程优先级别
  2. 线程同步

    对象互斥锁(synchronized)--保证共享数据操作的完整,这时就只有一个线程可以访问该对象/方法
    synchronized(this) {
     共享(同步)数据块
    }
    synchronized public void xx(){
     共享(同步)方法
    }
  3. 线程同步出现的问题

    死锁:
    1.在同步数据块内调用了其他同步代码-----减少同步锁定
    2.指定获取锁的顺序:比如规定,只有获得A锁的线程才有资格获取B锁
  4. synchronized

    1.synchronized进行加锁操作,synchronized的锁机制会根据线程竞争情况在运行时会有偏向锁(单一线程)、轻量锁(多个线程访问synchronized区域)、对象锁(重量锁,多个线程存在竞争的情况)、自旋锁等。该关键字是一个几种锁的封装。
    2.进入时,执行monitorenter(显式同步)将计数器+1,释放锁时计数器-1
    3.当一个线程判断到计数器为0时,则当前锁空闲,可以占用;反之,当前线程进入等待状态
  5. volatile

    1.volatile关键字是与Java的内存模型有关(主内存和工作内存)
    2.volatile可以直接与主内存产生交互,进行读写操作,保证可见性
    2.volatile能确保可见性:可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
    3.volatile禁止进行指令重排序。
    4.volatile变量可以保证下一个读取操作会在前一个写操作之后发生
  6. 线程池

    java.util.concurrent.ThreadPoolExecutor类就是一个线程池。
当前线程池大小:表示线程池中实际工作者线程的数量
最大线程池大小(maxinumPoolSize):表示线程池中允许存在的工作者线程的数量上限
核心线程大小(corePoolSize ):表示一个不大于最大线程池大小的工作者线程数量上限

线程code

  • 按顺序打印0~9--使用wait让未达到条件的线程进入等待态

    public class ThreadTest {
      private static final int endNum = 10;
      public static void main(String[] args) {
    //按需求新建多个线程,让每个线程实现对应的功能
          TTest[] test = new TTest[10];
          for(int i=endNum-1;i>=0;i--) {
              test[i] = new TTest(i);
              test[i].start();
          }
      }
    }
    public class TTest extends Thread {
      private static final int endNum = 10;
      static int orderNum = 0;
    //对象锁,只有获取该锁才能继续操作
      static Object object = new Object();
      private int printNum;
      public TTest(int printNum) {
          this.printNum = printNum;
      }
      @Override
      public void run() {
          synchronized (object) {
    //用户判断程序是否执行完毕
              while(orderNum < endNum) {
                  if(orderNum == printNum) {
                      System.out.println(printNum);
                      orderNum ++;
                      if(orderNum ==10) {
                          System.out.println("打印完成");
                      }
                      object.notifyAll();
                  }else {
                      try {
    //每个线程都对应一个参数,根据参数判断是否应该输出,如果不符合,当前线程就进入等待态,唤醒后再执行
                          object.wait();
                      } catch (Exception e) {
                          System.out.println("线程:"+printNum+"被打断了");
                          e.printStackTrace();
                      }
                  } 
              }
          }
      }
    }

ref:
java基础学习总结——线程(一)
你真的了解volatile关键字吗?
Java并发编程:volatile关键字解析

Set

  • hashSet

    无序,不可重复
public class Fish01 {
    public static void main(String args[]) {
        HashSet books = new HashSet();
        //分别向books集合中添加两个A对象,两个B对象,两个C对象
        books.add(new A());
        books.add(new A());
        books.add(new B());
        books.add(new B());
        books.add(new C());
        books.add(new C());
        System.out.println(books);
    }
}
class A{
    @Override
    public boolean equals(Object obj) {
        return true;
    }
}
class B {
    @Override
    public int hashCode() {
        return 1;
    }
}
//同时重写hashCode,equals方法,在集合中定义
class C {
    @Override
    public int hashCode() {
        return 2;
    }
    @Override
    public boolean equals(Object obj) {
        return true;
    }
}
//result
/home/sha/software/jdk/jdk-8u171-linux-x64/jdk1.8.0_171/bin/java -........
[cn.shafish.B@1, cn.shafish.B@1, cn.shafish.C@2, cn.shafish.A@677327b6, cn.shafish.A@14ae5a5]
Process finished with exit code 0
C类中重写hashCode,equals。定义两个对象相同,hashCode定位对象的存储位置(C类中返回hashCode值相同),equals判断对象值是否相等(C类中返回true)
B类中两个对象的引用值是不相等的,因为对象在内存中的地址单元不同(对于引用类型来说,默认是比较两个对象引用的地址)
A类对象的hashCode不同
  • LinkedHashSet

    元素的顺序总是与添加顺序一致(通过删除后再添加测试)
public class FIsh02 {
    public static void main(String[] args) {
        LinkedHashSet books = new LinkedHashSet();
        books.add("Java");
        books.add("LittleHann");
        System.out.println(books);
        //删除 Java
        books.remove("Java");
        //重新添加 Java
        books.add("Java");
        System.out.println(books);
    }
}
//result
[Java, LittleHann]
[LittleHann, Java]
  • TreeSet

    有序不重复
public class Fish03 {
    public static void main(String[] args) {
        TreeSet nums = new TreeSet();
        //向TreeSet中添加四个Integer对象
        nums.add(5);
        nums.add(2);
        nums.add(10);
        nums.add(-9);
        //输出集合元素,看到集合元素已经处于排序状态
        System.out.println(nums);
        //输出集合里的第一个元素
        System.out.println(nums.first());
        //输出集合里的最后一个元素
        System.out.println(nums.last());
        //返回小于4的子集,不包含4
        System.out.println(nums.headSet(4));
        //返回大于5的子集,如果Set中包含5,子集中还包含5
        System.out.println(nums.tailSet(5));
        //返回大于等于-3,小于4的子集。
        System.out.println(nums.subSet(-3 , 4));
    }
}
//result
[-9, 2, 5, 10]
-9
10
[-9, 2]
[5, 10]
[2]

List

  • ArrayList

    可以在创建它们时就指定initialCapacity大小,这样可以减少重新分配的次数,提高性能
public class Fish04 {
    public static void main(String[] args) {
        List books = new ArrayList();
        //向books集合中添加三个元素
        books.add(new String("算法导论"));
        books.add(new String("java编程思想"));
        books.add(new String("第一行代码"));
        System.out.println(books);
        //将新字符串对象插入在第二个位置
        books.add(1 , new String("疯狂Ajax讲义"));
        for (int i = 0 ; i < books.size() ; i++ )
        {
            System.out.println(books.get(i));
        }
        //删除第三个元素
        books.remove(2);
        System.out.println(books);
        //判断指定元素在List集合中位置:输出1,表明位于第二位
        System.out.println(books.indexOf(new String("疯狂Ajax讲义")));  //①
        //将第二个元素替换成新的字符串对象
        books.set(1, new String("LittleHann"));
        System.out.println(books);
        //将books集合的第二个元素(包括)
        //到第三个元素(不包括)截取成子集合
        System.out.println(books.subList(1 , 2));
    }
}
//result
[算法导论, java编程思想, 第一行代码]
算法导论
疯狂Ajax讲义
java编程思想
第一行代码
[算法导论, 疯狂Ajax讲义, 第一行代码]
1
[算法导论, LittleHann, 第一行代码]
[LittleHann]
  • Stack

    Stack后进先出
public class Fish05 {
    public static void main(String[] args) {
        Stack v = new Stack();
        //依次将三个元素push入"栈"
        v.push("算法导论");
        v.push("java编程思想");
        v.push("第一行代码");
        System.out.println(v);
        //访问第一个元素,但并不将其pop出"栈"
        System.out.println(v.peek());
        System.out.println(v);
        //pop出第一个元素
        System.out.println(v.pop());
        System.out.println(v);
    }
}
//result
[算法导论, java编程思想, 第一行代码]
第一行代码
[算法导论, java编程思想, 第一行代码]
第一行代码
[算法导论, java编程思想]

implementation 'de.hdodenhof:circleimageview:2.1.0'
implementation 'com.android.support:design:26.1.0'
  • xml布局文件导入menu的头部和功能选项(注销)

    //activity对应的xml文件
      <android.support.design.widget.NavigationView
          android:id="@+id/nav_view"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:layout_gravity="start"
          app:headerLayout="@layout/nav_header"
          app:menu="@menu/nav_menu" />
    //新建一个menu目录,建nav_menu.xml文件
    右键res-->Android Resource Direction-->在Resource type下拉框选menu...-->end
    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
      <group android:checkableBehavior="single">
          <item
              android:id="@+id/nav_logout"
              android:title="注销" />
      </group>
    </menu>
    //layout中新建nav_header.xml文件,ic_done图片顺便找一张
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="match_parent"
      android:layout_height="180dp"
      android:background="?attr/colorPrimary"
      android:padding="10dp">
      <de.hdodenhof.circleimageview.CircleImageView
          android:id="@+id/icon_image"
          android:layout_width="70dp"
          android:layout_height="70dp"
          android:layout_centerInParent="true"
          android:src="@drawable/ic_done" />
      <TextView
          android:id="@+id/username"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_alignParentBottom="true"
          android:textColor="#FFF"
          android:textSize="14sp" />
    </RelativeLayout>

    效果:

activity实现功能

private NavigationView navigationView;
//从application中获取用户信息(在head中显示用户名--忽略)
private MyApplication myApplication = MyApplication.getInstance();
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_index);
        。。。。。。
        //菜单栏设置点击事件
        menu();
    }
private void menu(){
        navigationView = findViewById(R.id.nav_view);
        //获取头布局文件
        View headerView = navigationView.getHeaderView(0);
        TextView textview = (TextView)headerView.findViewById(R.id.username);
        textview.setText(myApplication.getLoginUser().getUsername());
        navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(MenuItem item) {
//注销功能--忽略
                switch (item.getItemId()){
                    case R.id.nav_logout:
                        myApplication.userLogout();
                        Intent intent=new Intent(IndexActivity.this,MainActivity.class);
                  intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);
                        startActivity(intent);
                        break;
                }
                return false;
            }
        });
    }

ref:使用NaviGationView来配置SlidingMenu的左侧菜单——学习笔记

安卓和之前的j2ee大作业差不多就完结--这几天要做个总结||||||||||

  • 1.FLAG_ACTIVITY_CLEAR_TASK :如果在调用Context.startActivity时传递这个标记,将会导致任何用来放置该activity的已经存在的task里面的已经存在的activity先清空,然后该activity再在该task中启动,也就是说,这个新启动的activity变为了这个空tas的根activity.所有老的activity都结束掉。该标志必须和FLAG_ACTIVITY_NEW_TASK一起使用.
  • 2.FLAG_ACTIVITY_NEW_TASK: 首先会查找是否存在和被启动的Activity具有相同的亲和性的任务栈(即taskAffinity,注意同一个应用程序中的activity的亲和性一样,所以下面的a情况会在同一个栈中,前面这句话有点拗口,请多读几遍),如果有,刚直接把这个栈整体移动到前台,并保持栈中的状态不变,即栈中的activity顺序不变,如果没有,则新建一个栈来存放被启动的activity.

注销实现代码

//注销前用户本地数据删除等等操作
Intent intent=new Intent(IndexActivity.this,MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

refandroid如何实现账号注销功能

在Adapter中设置cardView的点击事件
需要定位用户点击的位置
问题:holder.getAdapterPosition()一直返回-1,而不是返回点击的位置

解决:使用tag解决

@Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (mContext==null){
            mContext=parent.getContext();
        }
        View view= LayoutInflater.from(mContext).inflate(R.layout.essay_item,parent,false);
//点击显示的资源后进入详细页面
        final ViewHolder holder = new ViewHolder(view);
        holder.cardView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //获取当前点击
                //int position = holder.getAdapterPosition();
               // getState((Integer) v.getTag());
//取出position
                int position =  (Integer) v.getTag();
                /*if(position == -1)+1
                    return;*/
                EssayItem fruit = mEssayItem.get(position);
                Intent intent = new Intent(mContext, CurrentItemActivity.class);
                intent.putExtra(CurrentItemActivity.FRUIT_NAME, fruit.getEssayTitle());
                intent.putExtra(CurrentItemActivity.FRUIT_IMAGE_ID, fruit.getImageId());
                LogUtil.d(TAG,fruit.toString());
                mContext.startActivity(intent);
            }
        });
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ListAdapter.ViewHolder holder, int position) {
        EssayItem essay=mEssayItem.get(position);
        holder.essayName.setText(essay.getEssayTitle());
        Glide.with(mContext).load(essay.getImageId()).into(holder.essayImage);
//记录当前position
        holder.itemView.setTag(position);
    }